0
votes

I am having a problem running my program in Clojure. I just start learning Clojure a couple of weeks ago. So I don't know the quick and easy way to debug a Clojure program. My func2 raises an exception at (adj(a b)) as followed:

ClassCastException java.lang.Long cannot be cast to clojure.lang.IFn user/func2.

I don't know what is wrong with it. Can someone point out the problem with my coding? And in func3, I call func2 recursively, but it throws:

ArityException Wrong number of args (0) passed to: PersistentVector clojure.lan g.AFn.throwArity (AFn.java:437)

What is wrong with func3? Thank you.

(defn adj [value1 value2]
    (def result (+ (/ value1 2) (/ value2 2)))  
    (if (= (mod result 2) 1)
        (+ result 1)
        result
    )
)

(defn func2 [list]
    (let [[a b c d] list] 
        (inc d)
        ([(adj c a) (adj a b) (adj b c) d]))    
)

(defn func3 [list]
    (loop [v list r []]

    (if(= (v 0) (v 1) (v 2))
        (conj list r)               
        (func3(func2(list)))
    ))
)
2

2 Answers

3
votes

What's the intended result of these functions? We probably need to see some sample inputs and expected results to really be able to help you.

Here's my attempt at cleaning them up. I've noted the changes I made as comments. func3 has the most serious problem in that it's an infinite recursion - there's no end condition. What should cause it to stop working and return a result?

(defn adj [value1 value2]
   ;; don't use def within functions, use let
  (let [result (+ (/ value1 2) (/ value2 2))]
    (if (= (mod result 2) 1)
      (+ result 1)
      result)))

(defn func2 [list]
  (let [[a b c d] list]
    ;; The extra parens around this vector were causing it
    ;; to be called as a function, which I don't think is
    ;; what you intended:
    [(adj c a) (adj a b) (adj b c) d]))

;; This needs an end condition - it's an infinite recursion
(defn func3 [list]
  (loop [v list r []]
    (if (= (v 0) (v 1) (v 2))
      (conj list r)
      ;; Removed extra parens around list
      (func3 (func2 list)))))

The reason I say not to use def within functions is that it always creates a global function. For local bindings you want let.

Regarding the extra parens, the difference between [1 2 3] and ([1 2 3]) is that the former returns a vector containing the numbers 1, 2, and 3, whereas the latter tries to call that vector as a function. You had excess parens around the literal vector in func2 and around list in func3, which was causing exceptions.

As a style note, the name list isn't a good choice. For one thing, it's shadowing clojure.core/list, and for another you're probably using vectors rather than lists anyway. It would be more idiomatic to use coll (for collection) or s (for sequence) as the name.

This would suggest at least one other change. In func3 you use a vector-only feature (using the vector as a function to perform lookup by index), so to be more general (accept other data structures) you can convert to a vector with vec:

(defn func3 [coll]
  (loop [v (vec coll) r []]
    (if (= (v 0) (v 1) (v 2))
      (conj v r)
      (func3 (func2 v)))))
0
votes

Oh, there is no need to debug that. I suggest you have a look at LightTable.

The first two functions are easily fixed:

(defn adj [value1 value2]
  ;(def result (+ (/ value1 2) (/ value2 2))) def creates a global binding in current namespace !!!  
  (let [result (+ (/ value1 2) (/ value2 2))]  
  (if 
    (= (mod result 2) 1)
    (inc result)
    result)))

(defn func2 [xx]
  (let [[a b c d] xx] 
    [ (adj c a) (adj a b) (adj b c) (inc d)]
    ))

The third function is not clear to me. I don't read your intent. What I understand is: "Keep applying func2 to itself until the first three elements of its result are equal." But I'm afraid this condition is never met, so I replaced it with a true in order to see just one result without blowing the stack.

(defn func3 [xx]
  (loop [ v (func2 xx) ]
    (if
      ;(= (v 0) (v 1) (v 2))
      true
      v               
      (recur (func2 v))
    )))

Useful link: http://clojure.org/cheatsheet

Cheers -