5

Clojure で 2 つ以上の s 式を返すマクロを作成する (または既存のマクロを使用する) 方法はありますか?

例。最初の 10 個の正方形を作成しようとしているとします。

(map * (range 10) (range 10))

ここで、repeatを使用して、後でパワー (今のところ 2) をパラメーターとして提供できるようにします。

(map * (repeat 2 (range 10)))

ただし、 repeatは 2 つの範囲ではなく 2 つの範囲を持つ単一の s 式を返すため、上記は機能しません。

「最初の 10 マスを返す」関数の代替実装を提供しないでください。このような状況に対処するための慣用的な方法や、一般的に適用可能な回避策に興味があります。

以下の爆発を実装する方法を探していると思います。

(explode '( a b c )) ;; evals to a b c
(map * (explode (repeat 2 (range 10)))
4

2 に答える 2

4

単一のマクロでこれを行うことはできません。

マクロは、S 式を受け取り、それを別の S 式に変換する関数です。入力は式 (シンボル、プリミティブ、その他の式など) の任意のシーケンスにすることができ、出力は元のマクロ呼び出しの代わりに挿入される単一の式です。

一般に、マクロは、フォーム全体をマップして変換する呼び出しを囲む必要があります

(your-macro-here (map * (repeat 2 (range 10))))

1 つは式を生成し、もう 1 つは外側のフォーム全体を包含する 2 つのマクロがある場合、外側のマクロはおそらくマクロの結果を含む単一の式を見つけ、この例では 2 つの範囲を検出し、それらを 1 レベル上げて独立した式にすることができます。 . 実際にこれを行うことはお勧めできません。マクロの機能を説明するのに役立つだけです。

于 2013-04-03T20:37:19.020 に答える
3

Arthur が言うように、マクロで探していることを正確に実行することはできません。これらのフォームで何をしたいかによっては、回避策が可能です。

マクロによって生成された複数のフォームを単純に評価したい場合 (定型コードを単純化するなど) は、これらの複数のフォームをフォームでラップできますdo

(defmacro defn-foos [& foos]
  `(do ~@(map (fn [foo] `(defn ~foo [])) foos)))

(defn-foos my-fn-1 my-fn-2)
;; expands as:
;; (do (defn my-fn-1 [])
;;     (defn my-fn-2 []))

展開されたフォームを関数呼び出しで位置引数として使用したい場合は、おそらくそれらを でラップしてから、関数への位置引数としてリストをアンパックする をlist使用することをお勧めします。apply

これがどのように機能するかを確認するには、元の質問の 2 番目の例を以下を使用して簡単に変更できることに注意してくださいapply

(apply map * (repeat 2 (range 10)))
于 2013-04-03T21:08:21.273 に答える