快速简单的黑客使用我作为clojure中的虚数

时间:2012-11-25 22:54:23

标签: clojure

我只需要i用于算法。我觉得导入clojure.math对于这样的任务来说太过分了。

为什么?

我不需要复杂的结果,实际上不需要虚部的实部。在我的实现中,我一次只使用一个值,并且永远不会将两者合并,除了乘法。输出最终没有引用i,虚拟部分只需要查看计算中符号的变化。

简单地说,如果有一种方法可以将i定义为:

,那就太好了
(def i (....) ) 

这样(* i i)等于-1

3 个答案:

答案 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复数库会更有意义。