给定[{a :a} {b :b}]
之类的绑定表格如何找到所有符号? (a b)
答案 0 :(得分:2)
天真的方法是将绑定表单视为一些嵌套集合,找到该集合中的所有符号,并返回这些符号的序列:
(defn symbols [x]
(filter symbol? (tree-seq coll? seq x)))
(symbols '[{a :a} {b :b}])
;;=> (a b)
然而,作为@amalloy noted,这并不适用于所有情况。以下是一些示例,其中symbols
的上述实现会产生不良结果:
;; & isn't actually bound to anything
(symbols '[foo & bar])
;;=> (foo & bar)
;; duplicates
(symbols '{x :foo :or {x :bar}})
;;=> (x x)
;; keys and default values are evaluated, not bound
(symbols '{x (keyword "foo") :or {x (keyword 'bar)}})
;;=> (x keyword x keyword quote bar)
;; namespaced keywords and symbols don't work
(symbols '{:keys [::foo :bar/baz qux/quux]})
;;=> (qux/quux)
他建议使用内置的destructure
函数,但正如他在答案中所证明的那样,这会导致一些垃圾出现在结果中:
(take-nth 2 (destructure '[{:keys [x]} (last y)]))
;;=> (map__10938 map__10938 x)
虽然这个技术上给出了Clojure将绑定的符号列表,但map__10938
只是一个实现工件,与解构语言本身无关。
值得庆幸的是,手动解析绑定表单并组装一组符号(从原始绑定表单中获取)并不太难:
(require '[clojure.set :as set])
(defn symbols [binding]
(cond
(symbol? binding)
#{binding}
(vector? binding)
(apply set/union (map symbols (remove #{'& :as} binding)))
(map? binding)
(apply set/union
(for [[k v] binding]
(case k
:or #{}
:as #{v}
(:keys :strs :syms) (set (map (comp symbol name) v))
(symbols k))))))
答案 1 :(得分:1)
更好的是使用~/.gradle/init.gradle
,它理解哪些符号是将被绑定的名称,而不是将被拆分的值。例如,考虑:
clojure.core/destructure
在这种情况下,您几乎肯定不希望在符号列表中包含(let [{:keys [x]} (last y)]
x)
,假设您使用它来更好地理解解构规范。如果你打电话给last
,它会告诉你究竟什么名字将被绑定到什么值:
destructure
现在一方面你得到一个实际上没有被调用者输入的符号,但这可能仍然有用,因为它告诉你Clojure实际上会做什么来处理这个user> (destructure '[{:keys [x]} (last y)])
[map__10938 (last y)
map__10938 (if (clojure.core/seq? map__10938)
(clojure.lang.PersistentHashMap/create (clojure.core/seq map__10938))
map__10938)
x (clojure.core/get map__10938 :x)]
表达式。要获得左侧,即要绑定的名称,您可以使用
let