2

clojure とそのマクロに惹かれ、初めて知った私は、「abc」などの文字のリストから長さ「n」のすべての文字列を生成するマクロを作成するタスクを自分自身に設定しました。したがって、n=2 の場合、出力は "aa" "ab" "ac" "ba" "bb" "bc" "ca" "cb" "cc" になります。テンプレートとして次の関数から始めました: (defn mkstr [nv] (for [ivjv] (str ij)))。for バインディングでの「v」の繰り返しと、「n」の関数である必要がある変数の数の作成。この特定のケースでは: 2.

'quote' 'unquote' などについて読んだ後、マクロに関する優れたオンライン チュートリアル、多くの試行錯誤、そして運が良ければ、次の関数とマクロを生成することができました。ん。本当に大変だったのは、「for」バインディングで必要な可変量のコードを生成することでした。

(defn mkvars [n] 
"Gives a list of 'n' unique symbols"
(let [vc (repeatedly n #(gensym ))] vc)) 

(defmacro mkcoms [n syms] 
"Generates a list of possible combinations of length 'n' from a string of symbols"
`(let [vs# (mkvars ~n) sy# ~syms  
    forarg# (vec (interleave vs# (repeat ~n sy#)))]
     `(for ~forarg# (str ~@vs#))))

ここで、私の「本当の」問題または理解の欠如は、出力を取得するには、次のようにしなければならないことです: (eval (mkcoms len chars))。これが「eval」を使用しないと機能しないのはなぜですか? 確かにそのまま使えますが、何か違和感があります。

4

1 に答える 1

2

マクロは引用符で囲まれたフォームを返します。これが、evalに渡すときに機能する理由です。マクロの目的が関数にあるのかわからないので、この説明があなたの求めているものであることを願っています。

マクロは、それが表すコードを生成して返すことになっています。マクロは引用符で囲まれたフォームを生成します。バッククォートの外層を削除すると、結果のコードではなく、展開を実行するコード(マクロ)の一部になることが意図されているように見えますが、マクロ展開時に実行されます。

(defmacro mkcoms [n syms]                                                                                                      
  "Generates a list of possible combinations of length 'n' from a string of symbols"                                           
  (let [vs     (mkvars n)                                                                                                      
        sy     syms                                                                                                            
        forarg (vec (interleave vs (repeat n sy)))]                                                                            
    `(for ~forarg (str ~@vs))))

これはあなたが求めているもののように聞こえますが、なぜこれを「コンパイル時」と実行時のどちらで発生させたいのか理解できません。

于 2012-12-01T15:47:58.843 に答える