let forms:如何访问宏中的结构化符号?

Val*_*nck 6 macros clojure destructuring

我正在尝试编写一个宏,它通过解构扩展为let形式.我的问题是我希望得到let表单中定义的符号列表,包括通过destruturing获得的符号.

用例

我试图将这种行为分解出来,例如验证:

(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)
       ))
Run Code Online (Sandbox Code Playgroud)

提出的解决方案

通过某种类型的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))
Run Code Online (Sandbox Code Playgroud)

我错过了什么

但是我错过了一些访问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)
     ))) 
Run Code Online (Sandbox Code Playgroud)

有谁知道我怎么可能这样做?

Mic*_*zyk 5

解构由clojure.core/destructure函数处理.它是公开的,所以我们可以自己调用它并提取所有本地的名称,包括那些命名用于解构的中间结果:

(defmacro and-let [bindings & tests]
  (let [destructured (destructure bindings)]
    `(let ~destructured
       (and ~@(take-nth 2 destructured)
            ~@tests))))
Run Code Online (Sandbox Code Playgroud)

似乎工作:

(let [foo nil]
  (and-let [a 1
            [b c] [2 3]]
    (nil? foo)))
;= true
Run Code Online (Sandbox Code Playgroud)