Могу ли я получить эту переменную в def? - PullRequest
3 голосов
/ 19 февраля 2010

Есть ли способ имитировать переменную this в чем-то вроде (def foo {:two 2 :three (inc (:two this))})? Еще лучше было бы что-то вроде (def foo {:two 2 :three (inc ::two)}). Мне сказали, что есть библиотека, которая делает именно это, но я не могу найти ничего подобного.

Спасибо!

Ответы [ 2 ]

4 голосов
/ 20 февраля 2010

Если вам нужно временное имя для чего-то, для этого let.

(def foo (let [x {:two 2}]
           (assoc x :three (inc (:two x)))))

Я не знаю ни одной библиотеки, которая делает то, что вы хотите.Время от времени кто-то предлагает «обобщенную стрелку», например ->, но с помощью магического символа вы можете вставить промежуточные выражения, которые будут заменены чем-то другим.См. Например здесь и здесь .Но эта идея имеет тенденцию быть сбитой, потому что она более сложна и запутанна для небольшой выгоды.let твой друг.Смотрите пример Рича:

(let [x []
      x (conj x 1)
      x (into x [2 3])
      x (map inc x)]
...) 
2 голосов
/ 20 февраля 2010

( Обновление: Переупорядочено и переработано. * Добавлено 1003 * и (эскиз) -m> макросов.)

Вы можете написать этот конкретный пример как

(def foo (zipmap [:two :three] (iterate inc 2)))

Самое простое общее решение, которое приходит мне в голову в этот момент:

user> (-> {} (assoc :two 2) (#(assoc % :three (inc (:two %)))))
{:three 3, :two 2}

Это на самом деле очень гибко, хотя для этого требуется, чтобы вы неоднократно выписывали assoc.

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

(defn build-map* [& kvs]
  (reduce (fn [m [k v]]
            (assoc m k (v m)))
          {}
          kvs))

(defmacro build-map [& raw-kvs]
  (assert (even? (count raw-kvs)))
  (let [kvs (map (fn [[k v]] [k `(fn [m#] (let [~'this m#] ~v))])
                 (partition 2 raw-kvs))]
    `(build-map* ~@kvs)))

user> (build-map :two 2 :three (inc (:two this)))
{:three 3, :two 2}

Вы можете легко изменить это, чтобы использовать предоставленный пользователем символ, а не жестко закодированный this.Или вы можете переключиться на %, который является обычным символом вне литералов анонимной функции.Возможно, добавьте явный начальный аргумент карты, назовите его -m> (для многопоточности карты), и вы можете сделать

(-m> {} :two 2 :three (inc (:two %)))

для того же результата.


Другой причудливый способ (в основномдля забавы):

;;; from Alex Osborne's debug-repl,
;;; see http://gist.github.com/252421
;;; now changed to use &env
(defmacro local-bindings
  "Produces a map of the names of local bindings to their values."
  []
  (let [symbols (map key &env)]
    (zipmap (map (fn [sym] `(quote ~sym)) symbols) symbols)))

(let [two 2
      three (inc two)]
  (into {} (map (fn [[k v]] [(keyword k) v]) (local-bindings))))
{:two 2, :three 3}

Обратите внимание, что это также захватит привязки, введенные любыми внешними формами let ...

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