【发布时间】:2012-10-29 21:07:23
【问题描述】:
try 在一个宏中,catch 在第二个宏中,由第一个宏调用。如何让以下工作?
(defmacro catch-me []
`(catch ~'Exception ~'ex
true))
(defmacro try-me []
`(try (+ 4 3)
(catch-me)))
扩展 try-me 看起来不错:
(clojure.walk/macroexpand-all '(try-me))
产量
(try (clojure.core/+ 4 3) (catch Exception ex true))
但调用 (try-me) 会产生:
"Unable to resolve symbol: catch in this context",
顺便说一句,这也是您在未尝试使用 catch 时会在 REPL 中收到的消息。
更新:
这就是我如何让它工作(感谢@Barmar),在这里你可以看到我的代码的实际上下文:
(defmacro try-me [& body]
`(try
~@body
~@(for [[e msg] [[com.mongodb.MongoException$Network "Database unreachable."]
[com.mongodb.MongoException "Database problem."]
[Exception "Unknown error."]]]
`(catch ~e ~'ex
(common/site-layout
[:div {:id "errormessage"}
[:p ~msg]
[:p "Error is: " ~e]
[:p "Message is " ~'ex]])))))
但这正是我所希望的(使用单独的宏 catch-me):
(defmacro try-me [& body]
`(try
~@body
(catch-me com.mongodb.MongoException$Network "Database unreachable.")
(catch-me com.mongodb.MongoException "Database problem.")
(catch-me Exception "Unknown error.")))
我认为这会更容易编写/维护。
有什么想法吗?我需要语法引用,因为我正在传递参数,这就是为什么不幸的是 Arthur 的答案无法应用(或者可以以某种方式应用?),但我直到现在才发布我的实际上下文。
【问题讨论】:
-
我目前的猜测是 (catch-me) 首先展开,然后才明确它在 try 中。是这样吗?如何对抗?
-
宏只在可以正常计算表达式的地方展开。
catch子表单不是被评估的表达式,它们是try语法的一部分。 -
我目前仍然认为这个问题没有答案。令人费解的是,为什么 Arthur 的示例有效,但使用语法引用的示例无效,而且,macroexpand-all 显示了一个有效的宏扩展,但直接调用它失败并出现错误。感谢 Barmar 的解决方法。还有其他想法吗?