我正在尝试编写一个允许我执行以下操作的宏
(without-nesting
(:= x 1)
(:= y 2)
(:= z 3)
(db-call x y z)
(:= p 33)
(db-call x y z p))
Run Code Online (Sandbox Code Playgroud)
变成
(let [x 1
y 2
z 3]
(db-call x y z)
(let [p 33]
(db-call x y z p)))
Run Code Online (Sandbox Code Playgroud)
到目前为止,我的实现如下
(defn assignment?
[[s _]]
(= s ':=))
(defmacro without-nesting
[& body]
(let [[bindings xs] (split-with assignment? body)
[non-bindings remaining] (split-with (complement assignment?) xs)]
`(let [~@(mapcat rest bindings)]
~@non-bindings
~(when (seq remaining)
`(without-nesting ~@remaining)))))
Run Code Online (Sandbox Code Playgroud)
我有问题什么时候remaining会是空的。在我当前的实现中nil,放置了一个防止最后一个表单non-bindings返回它的值。我不知道如何继续使用递归宏。有人可以帮忙吗
更新:
所以我能够摆脱 nil 但我只想知道是否有更好的方法来处理这个
(defmacro without-nesting
[& body]
(let [[bindings xs] (split-with assignment? body)
[non-bindings remaining] (split-with (complement assignment?) xs)]
`(let [~@(mapcat rest bindings)]
~@non-bindings
~@(if (seq remaining)
[`(without-nesting ~@remaining)]
[]))))
Run Code Online (Sandbox Code Playgroud)
这也是编写代码的好方法吗?或者你看到任何警告?对我来说,与嵌套相比,它看起来更线性let
我确实看到 ppl 可能会滥用这一点。在 的情况下let,如果嵌套变得太多,那么这是重构代码的提示。这可能会隐藏
只需使用let. 它已经是递归的。要将函数调用合并到您只关心副作用的地方,约定是绑定到下划线。
(let [x 1
y 2
z 3
_ (db-call x y z)
p 33
_ (db-call x y z p)])
Run Code Online (Sandbox Code Playgroud)