我发现自己正在编写一个函数来传递封闭let表达式中绑定的每个变量。这个场景的简化形式,在psuedocode中,是
(let [a 1 b 2 c 3 d 4 e 5 f 6]
(do-something a b c d)
(f a b c d e f g)
(compute-another-thing a c))
而我想写一些更像......
的东西(let env-name [a 1 b 2 c 3 d 4 e 5 f 6]
(do-something (take 4 env-name))
(f env-name)
(compute-another-thing a c))
那就是,clojure核心(或外部和可靠的东西)是否提供了一个let
变体,它将所有绑定收集到一个带有名称的集合中?
答案 0 :(得分:2)
解构会让你成为那里的一部分:
(let [[a b c d e f :as env-name] [1 2 3 4 5 6]]
(apply do-something (take 4 env-name))
(apply f env-name)
(compute-another-thing a c))
注意在使用env-name调用函数时必须使用 apply 。
对于更优雅的东西(比如你提出的表格),我认为你必须编写自己的宏。
更新:这是一个(非常轻微测试的)宏,可以处理简单的情况:
(defmacro let-as
[as-bind-name bindings & body]
(let [lhs-bindings (map first (partition 2 bindings))]
`(let ~bindings
(let [~as-bind-name [~@lhs-bindings]]
~@body))))
只要普通let-bindings的左侧是简单符号(即不使用解构),这应该可以执行您想要的操作。
一些REPL互动说明:
core> (let-as env-name [a 1 b 2 c 3 d 4 e 5 f 6] (print env-name) (apply + env-name))
[1 2 3 4 5 6]
21
一些破坏行为很好:
core> (let-as env-name [[a b] [1 2] [c d] [3 4]] (print env-name) (map first env-name))
[[1 2] [3 4]]
(1 3)
其他解构不是:
core> (let-as env-name [{:keys [a b]} {:a 1 :b 2}] (print env-name) (+ a b))
[{:keys [1 2]}]
3
这可以解决,但宏必须更复杂
答案 1 :(得分:1)
解构可能是最好的解决方案,但出于兴趣的考虑,Fogus在evalive project中得到了一个词汇上下文宏。它看起来像这样:
(defmacro lexical-context
[]
(let [symbols (keys &env)]
(zipmap (map (fn [sym] `(quote ~sym))
symbols)
symbols)))
(let [a 1]
(let [b 2]
(lexical-context))) ; => {a 1, b 2}
它使用宏可用的特殊&env
变量,因此您甚至不需要使用其他形式的let
。