2017-06-01 9 views
1

私はマクロを持っていますdefprinterここで関数を定義することができます。Clojureマクロ:シンボルが定義されている場合にのみアクションを実行します

これは次のようになります。だから私は(defprinter print-lemons {to-print :lemons})ような何かをしてから(print-lemons {:lemons "lemons"})、それが正しい事を出力します(と私は、最初の引数に構造化代入のあらゆる種類のプリンタを定義することができます)することができます

(defmacro defprinter [name pattern] 
    (list 'defn name [pattern] '(prn to-print))) 

しかし、今私は多分、同様の色で印刷する方法を知っている機能のオプションを提供したい、などの記号colorが定義されている場合、それは(prn color "-colored " to-print)を行う必要がありますが、それ以外だけ(prn color)

したがって、(defprinter print-lemons {to-print :lemons})で生成される関数は上記と同じになりますが、(defprinter print-lemons {to-print :lemons, color :color})は色付きバージョンを実行する関数を作成します。

さらに、私は (let [color "black"] (defprinter print-lemons {to-print :lemons}))または(def color "black") (defprinter print-lemons {to-print :lemons})と同じ効果が欲しいです。

これは可能ですか?

私はそれを次のように書いて試してみた:colorが定義されていない場合はRuntimeExceptionで失敗し、その後、私の理解マクロは、実行時に式をevalにしようとする書き込みをする関数で

(defmacro defprinter [name pattern] 
    (list 'defn name [pattern] 
    '(try (eval '(prn (str color "-colored " to-print))) 
     (catch java.lang.RuntimeException _ 
      (prn to-print))))) 

を(prn to-print)を実行します。実行時にcolorの存在をチェックしても、マクロが展開されるときにコンパイル時にto-print(常にその関数のために存在する必要がある)がチェックされます。

しかし、colorが定義されていても、私はいつもRuntimeExceptionを取得します(たとえ私がeval文にto-printだけ残しても、それを見つけることはできませんが、catchの節はうまく動作します)。私がevalの間に期待していたように、シンボルが解決されていないように見えますが、これを達成する他の方法は考えられません。

提案がありますか?

答えて

0

resolveの機能がこれで役立つでしょう。現在の名前空間でシンボルが表すものを返します。そうでない場合はnilを返します。 if式に入力することができます。

user> (resolve 'asdf) 
nil 
user> (if (resolve 'asdf) :defined :not-defined) 
:not-defined 

テストで解決したい記号を覚えておいてください。

2

最初に、ここで作業している2つの懸案事項を分割することはおそらく意味があります:関数の定義と、使用可能なvars/localsに基づいた印刷方法の決定。マクロをできるだけシンプルにすると、何が起こっているのかを簡単に把握できる傾向にあります。

印刷するかを決定する際には、あなたが本当に3例があります。

  1. colorは地元
  2. colorですが、私は推測する、VAR(またはクラスですか?)
  3. color

&envは、あなたがローカルとして利用できる何を見てみましょうマクロ内でのみ利用でき、有用でめったに使われないツール()で定義されていません。

resolveには、その名前のヴァールが表示されます。

は、したがって、この例では、def-color-printerで定義された関数の本体を作ることができ3つの潜在的な表現があります

(defn make-print-expression [env] 
    (if (contains? env 'color) 
    `(prn (str ~'color "-colored " ~'to-print)) 
    (if-let [color (resolve 'color)] 
     `(prn (str @~color "-colored " ~'to-print)) 
     `(prn ~'to-print)))) 

(defmacro def-color-printer [name pattern] 
    (list `defn name [pattern] 
     (make-print-expression &env))) 

(def-color-printer print-limes {to-print :limes}) 

(let [color "green"] 
    (def-color-printer print-limes-color-with-local {to-print :limes})) 

(def color "greyish") 
(def-color-printer print-limes-color-with-var {to-print :limes}) 

(print-limes {:limes "limes!"}) 
;=> "limes!" 

(print-limes-color-with-local {:limes "limes!"}) 
;=> "green-colored limes!" 

(print-limes-color-with-var {:limes "limes!"}) 
;=> "greyish-colored limes!" 

私も構文引用構文は不慣れである場合にはa blog about Clojure's quotingを書きました。

関連する問題