有没有办法模仿像this
这样的(def foo {:two 2 :three (inc (:two this))})
变量?更好的是(def foo {:two 2 :three (inc ::two)})
。我被告知有一个库正是这样做的,但我找不到任何类似的东西。
谢谢!
答案 0 :(得分:4)
如果您想要某个临时名称,那就是let
的用途。
(def foo (let [x {:two 2}]
(assoc x :three (inc (:two x)))))
我不知道任何你想做的事情的图书馆。每隔一段时间,有人会建议一个“广义箭头”,如->
,但有一个神奇的符号,你可以坚持中间表达式,这将被其他东西取代。例如,请参阅here和here。但是这个想法往往被击落,因为它更复杂,而且收效甚微。 let
是你的朋友。见Rich的例子:
(let [x []
x (conj x 1)
x (into x [2 3])
x (map inc x)]
...)
答案 1 :(得分:2)
(更新:重新排列并重新设计。build-map
和(草图)-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
。或者您可以切换到%
,这只是匿名函数文字之外的常规符号。也许添加一个显式的初始map参数,称之为-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表单引入的绑定...