(* i i)
に評価したい場合は-1
、マクロを準備する必要があります。
(ns user)
(defmacro *
[& args]
(let [i-count (count (filter #(= % 'i) args))
error #(throw (Exception. "Illegal number of imaginary units."))
i-factor (case (mod i-count 4)
0 1
2 -1
(error))]
`(clojure.core/* ~@(conj (filter #(not= % 'i) args) i-factor))))
マクロは通常の乗算に展開され、実数の乗算を妨げません。
user=> (macroexpand '(* i i))
(clojure.core/* -1)
user=> (macroexpand '(* i i 5 i 6 i))
(clojure.core/* 1 5 6)
user=> (macroexpand '(* 1.3 3.7))
(clojure.core/* 1 1.3 3.7)
user=> (macroexpand '(* i (+ 2 3) i))
(clojure.core/* -1 (+ 2 3))
マクロは必要ですか?マクロi
が存在しない場合(* i i
) が評価されます。それらは定義されていないため、コンパイル時エラーが発生します。質問で示唆されているように、処理方法を知ってi
いる値として定義できます。*
それは可能ですが、実行時に評価されます。clojure.core/*
マクロの明確な利点は、コンパイル中に評価され、上記の例に示すように通常の呼び出しに置き換えられることです。簡単に言えば速いです。