( Обновление: Переупорядочено и переработано. * Добавлено 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 ...