这个问题与两个宏之间的相互作用有关,一个宏包含在另一个宏中。所描述的两个宏是说明交互作用的例子,而不是唯一的例子。
考虑一个简单的clojure宏,它会产生副作用,但在其他情况下将其输入传递不变。
(defmacro echo [action & args]
`(fn [tru#] (do (~action ~@args tru#) tru#)))用法
((echo log/info "result") :foo)将该宏包含在另一个宏中,例如->>宏。我的直觉是这样做的:
(->> :foo (echo log/info "result") clojure.pprint/pprint)当->>宏先插入并插入:foo时,这是不起作用的,这会给回显宏留下错误的参数。纠正这一问题的一种方法是引入额外的括号,但在我看来,这似乎很难看:
(->> :foo ((echo log/info "result")) clojure.pprint/pprint)丑陋的意思是它闻起来像c宏。
发布于 2018-03-19 23:40:36
这里没有什么令人惊讶的事情,但是我认为echo扩展到一个函数会让人更难理解。macroexpand可以帮助说明所发生的事情:
(macroexpand '(->> :foo (echo prn "result") clojure.pprint/pprint))
=> (clojure.pprint/pprint (echo prn "result" :foo))在这里,您可以看到->>正确地将参数线程处理到echo表单的第二个/最后一个位置,这不是您想要的,因为echo扩展到一个必须用:foo作为其唯一参数调用的函数。如果我们扩展您的另一个示例:
(macroexpand '(->> :foo
((echo prn "result"))
clojure.pprint/pprint))
=> (clojure.pprint/pprint ((echo prn "result") :foo))您可以看到,在线程处理之后,您的echo调用就像上面的工作示例一样形成为((echo prn "result") :foo)。这里的宏之间没有奇怪的交互,只是语法混乱,因为echo扩展到了必须调用的函数。
我认为如果echo扩展为代码而不是匿名函数,这将更加清晰/清晰(从宏扩展的角度来看)。但是,我认为没有宏就可以达到同样的效果,这通常是比较好的:
(defn echo [f x & args]
(do (apply f x args)
(last args))
(->> :foo
(echo prn "result")
(clojure.pprint/pprint))
;; "result" :foo
;; :foo
;; => nil尽管还有其他方法来“监视”线程宏中的值。例如,试试这个:
(-> :foo
(doto (prn "result"))
(clojure.pprint/pprint))
;; :foo "result"
;; :foo
;; => nilhttps://stackoverflow.com/questions/49373381
复制相似问题