我只需要i
用于算法。我觉得导入clojure.math
对于这样的任务来说太过分了。
为什么?
我不需要复杂的结果,实际上不需要虚部的实部。在我的实现中,我一次只使用一个值,并且永远不会将两者合并,除了乘法。输出最终没有引用i
,虚拟部分只需要查看计算中符号的变化。
简单地说,如果有一种方法可以将i
定义为:
(def i (....) )
这样(* i i)
等于-1
。
答案 0 :(得分:3)
如果您希望(* 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/*
调用所取代,如上例所示。简单地说,它很快。
答案 1 :(得分:1)
这样的事情很快被黑了*?
(defn hacked-* [& args]
(let [[i-amount product]
((juxt (comp count filter)
(comp #(apply * %) remove))
#{:i} args)]
(if (and (> i-amount 0) (even? i-amount))
(- product)
product)))
(hacked-* 1 2 3) => 6
(hacked-* 1 2 3 :i :i) => -6
(hacked-* 1 2 3 :i :i :i) => 6
你可以在词法上将*重新绑定到黑客版本以评估复杂的表达式:
(let [* hacked-*]
(* 1 :i 2 :i 3 :i (* :i :i))) => -6
答案 2 :(得分:0)
这是我的hack,假设参数都是虚构的:
(defn im* [& i] ((fn [q n] (([* str * str] q) ([1 'i -1 '-i] q) n)) (mod (count i) 4) (reduce * i)))
...太可怕了!但是如果没有例如黑客Numbers.java来调度java.lang.Number的新子类,那么你要求的是不可能的。真的,使用Java或Clojure复数库会更有意义。