Перегрузка ключевых слов в Clojure - PullRequest
6 голосов
/ 07 апреля 2011

У меня есть такая карта:

(def a {:a 1, :b 2})

: Я хочу перегрузить карту, чтобы некоторые ключевые слова выполняли функции так:

(c: a)

Может выполнять функцию. Это возможно?

Обновление:

Я понимаю, что мог бы сделать что-то вроде:

(def a {:a (fn[] 1) :b (fn[] 2) :c (fn[] x)})

: и:

((c: a))

: но затем я должен преобразовать каждую существующую запись на карте в функцию.

Я хочу, чтобы функция каждый раз переоценивалась. Например, когда я делаю:

(def ab{:a 1         :b 2         :c ( #(.nextInt (java.util.Random.) 1000))}) 

(str (:c ab) " " (:c ab) " " (:c ab))

Я получаю:

61 61 61

Вместо трех разных чисел

Обновление 2

Я подумал об ответе, который мне дали, и понял, что он прав, я должен использовать только неизменные структуры. Окончательное решение, которое я придумал, заключалось в том, чтобы иметь функцию «обогащения», которая создает динамические свойства по требованию.

 (def a {:a 1, :b 2})

: Я хочу перегрузить карту, чтобы некоторые ключевые слова выполняли функции так:

(str (:c (enrich ab)) " " (:c (enrich ab)) " " (:c (enrich ab)))

будет каждый раз выдавать разные числа, например:

58 639 710

Ответы [ 3 ]

4 голосов
/ 08 апреля 2011

Я считаю, что можно переопределить поведение ассоциативных поисков, если вы сделаете свою структуру данных записью, а не регулярной картой.

В основном вам нужно переопределить clojure.lang.ILookup: see этот вопрос для более подробной информации

Вот краткий пример:

(deftype TestLookup []
  clojure.lang.ILookup
    (valAt [this k not-found]
      (str "Generated value for key - " k))

    (valAt [this k]
      (.valAt this k nil)))

(def lookupable-object (TestLookup.))

(:somekey lookupable-object)
=> "Generated value for key - :somekey"
2 голосов
/ 08 апреля 2011

Clojure предпочитает чистые структуры данных над объектами, которые сочетают данные и поведение.Вы можете получить желаемое поведение, обратившись к своей структуре данных через функцию:

(def base-foo {:a 1, :b 2})

(defn foo [key]
  (if (= :c key) 
    (rand-int 100)
    (get base-foo key)))

(str (foo :c) " " (foo :c) " " (foo :c))

;;=> "66 52 25"
2 голосов
/ 07 апреля 2011

Использование одной и той же карты для передачи обратно неизменяемых значений, а иногда и для передачи нечистых функций, мне кажется, противоречит духу того, для чего следует использовать неизменяемые карты. Вместо этого я бы рекомендовал использовать ссылочный тип, который указывает на неизменяемую карту только со значениями данных. Затем, когда одно из этих значений данных должно быть чем-то другим, укажите ваш тип ссылки на новую неизменяемую карту, отражающую любые изменения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...