我正在尝试编写一个宏,它扩展为一个destructuring的let表单。我的问题是,我想要在let形式中定义的符号列表,包括那些通过重构获得的符号。
用例
我试图将这类行为考虑在内,例如,验证:
(let [a (foo bar)
{x :x,
y :y,
{u :u, v: v :as nested-map} :nested} some-map]
(and x y nested-map u v ; testing truthiness
(valid-a? a)
(valid-x? x)
(valid-y? y)
(valid-nested? nested-map)
(valid-u-and-v? u v)
))提出的解决方案
通过某种and-let宏来实现这一点将是非常好的,我可以这样称之为:
(and-let [a (foo bar)
{x :x,
y :y,
{u :u, v: v :as nested-map} :nested} some-map]
(valid-a? a)
(valid-x? x)
(valid-nested? nested-map)
(valid-u-and-v? u v))我错过了什么,
但我缺少某种方式来访问在let表单中绑定的符号列表。如果我有类似于list-bound-symbols函数的东西,我可以这样做:
(defmacro and-let
"Expands to an AND close that previouly checks that the values declared in bindings are truthy, followed by the tests."
[bindings & tests]
(let [bound-symbols (list-bound-symbols bindings) ;; what I'm missing
]
`(let ~bindings
(and
~@bound-symbols
~@tests)
))) 有人知道我该怎么做吗?
发布于 2014-04-22 10:25:23
析构由clojure.core/destructure函数处理。它是公开的,因此我们可以自己调用它,并提取所有本地用户的名称,包括那些命名用于破坏的中间结果的名称:
(defmacro and-let [bindings & tests]
(let [destructured (destructure bindings)]
`(let ~destructured
(and ~@(take-nth 2 destructured)
~@tests))))似乎奏效了:
(let [foo nil]
(and-let [a 1
[b c] [2 3]]
(nil? foo)))
;= true发布于 2014-04-22 11:30:56
您可以通过一个直接处理映射的函数来完成这些操作。
(defn validate [vm ; validation map
dm ; data map
]
(and
(every? identity (map #(% dm) (flatten (keys vm))))
(every? identity (map (fn [[k vf]]
(if (vector? k)
(apply vf (map #(% dm) k))
(vf (k dm))))
vm))))例如
(validate {:s string?, :n number? :m number? [:m :n] > } {:s "Hello!", :m 5, :n 3})
; true
(validate {:s string?, :n number? :m number? [:m :n] > } {:s "Hello!", :m 5, :n 6})
; false
(validate {:s string?, :n number? :m number? :u \b [:m :n] > } {:s "Hello!", :m 5, :n 6})
; false您可以事先将示例中的任何无关变量( a )添加到映射中。这将不必要地测试a的真实性。没有造成伤害?
https://stackoverflow.com/questions/23216696
复制相似问题