0
votes

I'm new to clojure and I am trying to make a small program that does math with complex numbers. I've tried multiple versions of the multiply function and they all give the same error. For some other functions, using let fixed it but not here. im-make just returns a vector with the real and imaginary numbers.

(defn im-mult
  ([i j]
    (let [a (first i)
          b (second i)
          x (first j)
          y (second j)]
  (im-make (- (* (a) (b)) (* (x) (y)))
             (+ (* (a) (b)) (* (x) (y)))))))

given two vectors with a real and imaginary number, => (im-mult x y)

ClassCastException java.lang.Long cannot be cast to clojure.lang.IFn ComplexMath.core/im-mult (NO_SOURCE_FILE:7)

I just want to say, wow! Didn't think clojure had this much backing around here, thanks for the suggestions, the error was of course parenthesis and incorrect multiplying.

2
For imaginary numbers z1 = (a + bi), z2 = (c + di), their product is z1 * z2 = (ac-bd)+(ad+bc)i. So, if (im-mult z1 z2) = z1 * z2, then (defn im-mult [[a b] [c d]] [(- (* a c) (* b d)), (+ (* a d) (* b c))]).A. Webb
Yeah this code was incorrectly calculating at first, poorly ported from java and I didn't pay much attention about what multiplies with what. Thanks!user3133608

2 Answers

2
votes

1) you need to get rid of the extra parens around a, b, x, and y.

2) anytime you see a bunch of first and second, that's a good clue that you should be destructuring your inputs instead:

(defn im-mult
  [i j]
  (let [[a b] i
        [x y] j]
    (im-make (- (* a b) (* x y))
             (+ (* a b) (* x y)))))

I would always recommend this over #1. This might be a good place to stop for readability, but for grins we can keep pushing it...

3) I observe that (* a b) and (* x y) are used twice, so there is really no need to destructure at all - we can just apply * to i and j:

(defn im-mult
  [i j]
  (let [ab (apply * i)
        xy (apply * j)]
    (im-make (- ab xy)
             (+ ab xy))))

4) I observe that you're applying the same operation to both inputs, so might as well map the operation across the inputs.

(defn im-mult
  [i j]
  (let [m (map #(apply * %) [i j])]
    (im-make (apply - m)
             (apply + m))))

5) Same observation for - and +...

(defn im-mult
  [i j]
  (let [m (map #(apply * %) [i j])
        s (map #(apply % m) [- +])]
    (apply im-make s)))

At this point, it's admittedly harder to see the intent of the code. However, I think one reason is that you've fixed the number of inputs to 2. My suspicion is that there is an n-dimensional algorithm here and taking [& i] as inputs would lead you to a more beautiful place while also improving the code.

0
votes

Those extra parentheses aroung a, b, x and y are not needed. Besides, they make Clojure try to interpret numbers as functions. This should fix it:

(defn im-mult
  ([i j]
    (let [a (first i)
          b (second i)
          x (first j)
          y (second j)]
      (im-make (- (* a b) (* x y))
           (+ (* a b) (* x y))))))