(defmacro block [ctx & expr]
`(let [~@(mapcat (fn [[k v]] [k `~v]) ctx)]
~@expr
))
(defn action1 [] (print "action1") (rand-nth [true false]))
(defn action2 [] (print "action2") (rand-nth [true false]))
( block { __blockaddrabsolute "1_1" __blockaddr "1_1"}
( block {typeofparent "ummutate" __nodeid "c21f80" __blockaddr "1_1_1"} ( action1 ))
( block {__blockaddrabsolute "1_1_2" __nodeid "c60590" __blockaddr "1_1_2"} ( action2 ))
( block {__blockaddrabsolute "1_1_3" __nodeid "c60595" __blockaddr "1_1_3"} ( action1 ))
( block {__blockaddrabsolute "1_1_4" __nodeid "c60596" __blockaddr "1_1_4"} ( action2 ))
"end" )
如果任何操作返回false,我想中断宏评估的执行。
预期输出:
action1 true
action2 true
action1 false
答案 0 :(得分:2)
您所需的短路行为可通过if
/ when
形式获得,因此我们可以使用宏将 body 中的一系列形式转换为嵌套的{ {1}}表格:
when
然后,如果我们(defmacro block [bindings & body]
(let [whens (reduce (fn [acc elem]
`(when ~elem ~acc))
(last body)
(reverse (butlast body)))]
`(let [~@(mapcat (fn [[k v]] [k `~v]) bindings)]
~whens)))
您的示例macroexpand
表格,我们将得到此格式(出于可读性考虑而对其进行了重新格式化):
block
因为您的(let* [__blockaddrabsolute "1_1" __blockaddr "1_1"]
(when (block {typeofparent "ummutate", __nodeid "c21f80", __blockaddr "1_1_1"} (action1))
(when (block {__blockaddrabsolute "1_1_2", __nodeid "c60590", __blockaddr "1_1_2"} (action2))
(when (block {__blockaddrabsolute "1_1_3", __nodeid "c60595", __blockaddr "1_1_3"} (action1))
(when (block {__blockaddrabsolute "1_1_4", __nodeid "c60596", __blockaddr "1_1_4"} (action2))
"end")))))
/ action1
函数返回随机布尔值,您将获得不同的结果,但是您确实获得了所需的短路行为。如果任何嵌套表单未通过action2
测试,则最终结果将为nil。
我会考虑通过引入更集中,通常更有用的类似when
的宏来重构此宏,当它的任何内部形式不真实且根本不关心绑定时,它就会短路。然后将do
用于内部绑定:
let