可以尝试捕获不同(但嵌套)的宏?

0dB*_*0dB 6 macros clojure try-catch

try是在一个宏时,catch在由第一被叫的第二个.如何让以下工作?

(defmacro catch-me []
  `(catch ~'Exception ~'ex
     true))

(defmacro try-me []
  `(try (+ 4 3)
        (catch-me)))
Run Code Online (Sandbox Code Playgroud)

扩展try-me看起来很好:

(clojure.walk/macroexpand-all '(try-me))
Run Code Online (Sandbox Code Playgroud)

产量

(try (clojure.core/+ 4 3) (catch Exception ex true))
Run Code Online (Sandbox Code Playgroud)

但是打电话(试试我)产量:

"Unable to resolve symbol: catch in this context",
Run Code Online (Sandbox Code Playgroud)

BTW,这也是你在不尝试时使用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]])))))
Run Code Online (Sandbox Code Playgroud)

但这是我希望的(使用单独的宏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.")))
Run Code Online (Sandbox Code Playgroud)

我认为这会更容易编写/维护.

有任何想法吗?我需要语法引用,因为我传递参数,这就是为什么不幸的是亚瑟的答案不能应用(或者它可以以某种方式?),但我直到现在才发布我的实际上下文.

Bar*_*mar 5

您收到该错误的原因是因为语法为try:

(try expr* catch-clause* finally-clause?)
Run Code Online (Sandbox Code Playgroud)

这意味着在catchfinally子句之前可以有任意数量的expr形式.扫描s直到找到以or 开头的那个.它扩展任何宏之前执行此操作,因为它只是试图找出exprs和catch/finally子句的开始位置.它收集所有和子句并为它们建立适当的错误处理环境.tryexprcatchfinallycatchfinally

一旦这样做,它就会expr正常执行所有表单.所以它扩展了它们的宏,然后执行它们.但catch它不是一种功能或特殊形式,它只是try在前一步中寻找的东西.因此,当它正常执行时,您会得到与将其键入REPL时相同的错误.

你应该做的就是编写一个宏,你可以将整个代码扩展到你想要的try/ catch表达式.如果没有您想要完成的任何示例,很难给出具体的答案.