问题描述
给定一个绑定形式如 [{a:a} {b:b}]
如何找到所有的符号? (ab)
绑定表单作为一些嵌套集合,找到该集合中的所有符号,并返回这些符号的序列:
[x]
(过滤器符号?(tree-seq coll?seq x)))
(符号'[{a:a} {b:b}])
;; => (ab)
但是,,这在所有情况下都不会工作。下面是一些示例,其中上述实现符号
给出了不希望的结果:
;; &实际上并不绑定任何东西
(symbols'[foo& bar])
;; => (foo& bar)
;;重复
(symbols'{x:foo:或{x:bar}})
;; => (x x)
;;键和默认值被评估,不绑定
(符号'{x(关键字foo):或{x(关键字bar)}})
;; => (x关键字x关键字引用栏)
;;命名空间的关键字和符号不工作
(符号'{:keys [:: foo:bar / baz qux / quux]})
;; => (qux / quux)
他建议使用内置的,但是如他在他的回答中所示,这会导致一些垃圾显示在结果中:
(take-nth 2(destructure'[{:keys [x] ]))
;; => (map__10938 map__10938 x)
虽然这在技术上 Clojure将绑定, map__10938
只是一个实现工件,并且与解构语言本身无关。
(require'[clojure.set:as set])
(defn symbols [binding]
(cond
$ b $ {binding}
(vector?binding)
(apply set / union(map symbols(remove#{'&:as} binding)))
(map?binding)
(apply set / union
[for [[kv] binding]
(case k
:or#{}
作为#{v}
(:keys:strs:syms)(set(map(comp symbol name)v))
(symbols k)))))
Given a binding form such as [{a :a} {b :b}]
how can I find all the symbols? (a b)
The naïve approach would be to just treat the binding form as some nested collection, find all the symbols in that collection, and return the sequence of those symbols:
(defn symbols [x]
(filter symbol? (tree-seq coll? seq x)))
(symbols '[{a :a} {b :b}])
;;=> (a b)
However, as @amalloy noted, this won't work in all cases. Here are some examples where the above implementation of symbols
gives an undesirable result:
;; & 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)
He suggests using the built-in destructure
function instead, but as he demonstrated in his answer, this causes some garbage to show up in the result:
(take-nth 2 (destructure '[{:keys [x]} (last y)]))
;;=> (map__10938 map__10938 x)
While this technically gives the list of symbols that Clojure will bind, that map__10938
is just an implementation artifact, and has nothing to do with the destructuring language itself.
Thankfully, it's not too hard to parse the binding form manually and assemble a set of the symbols, taken from the original binding form, that would be bound:
(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))))))
这篇关于如何找到绑定形式的所有符号?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!