6

try1 つのマクロにありcatch、最初のマクロによって呼び出される 2 番目のマクロにあります。以下を機能させるにはどうすればよいですか?

(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",

ところで、これは、try ではないときに 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.")))

これは、作成/保守が簡単になると思います。

何か案は?パラメータを渡しているため、構文の引用が必要です。そのため、残念ながらアーサーの答えを適用できません(または何とかできますか?)が、実際のコンテキストを今まで投稿していませんでした。

4

2 に答える 2

5

そのエラーが発生する理由は、構文が次のとおりであるためtryです。

(try expr* catch-clause* finally-clause?)

これは、 catch句とfinally句の前に任意の数のexprフォームが存在できることを意味します。またはで始まるものが見つかるまで、 をスキャンします。これは、exprs 節と catch/finally 節がどこから始まるかを把握しようとしているだけなので、マクロを展開する前にこれを行います。すべてのand句を収集し、適切なエラー処理環境を確立します。tryexprcatchfinallycatchfinally

これが完了すると、すべてのexprフォームが正常に実行されます。そのため、マクロを展開して実行します。しかしcatch、関数や特別な形式ではなくtry、前のステップで探すものです。したがって、通常どおり実行すると、REPL に入力したときと同じエラーが発生します。

tryおそらくすべきことは、必要な/catch式に展開されるコード全体をラップするマクロを作成することです。達成しようとしていることの例がなければ、具体的な答えを出すのは困難です。

于 2012-10-29T22:35:05.053 に答える
1

簡単な答えは YES ですが、特別な形式でマクロをネストすると、このような二重引用符の問題が発生する可能性があります。展開の両方のレベルでシンボルが評価されないようにする必要があります。

user> (defmacro catch-me []                                   
          '(list 'catch 'Exception 'ex  
                       'true))

user> (defmacro try-me []
    `(try (+ 4 3)              
                  ~(catch-me)))
#'user/try-me

user> (try-me)
7

また、例外もキャッチされることを確認するには:

user> (defmacro try-me []
    `(try (/ 4 0)
              ~(catch-me)))
#'user/try-me
user> (try-me)
true
于 2012-10-29T22:38:55.157 に答える