How to abstract a list in order to manipulate it in other functions in Clojure?

Viewed 90

I'm very new to functional languages and I'm attempting to implement a simple append function in Clojure. My code:

(defn append
  [lizt1 lizt2]
  (cond
    (empty? lizt1) lizt2
    :else (def sq (cons (first sq lizt1) (append (rest sq lizt1) lizt2)))))

(let [x (quote (1 2 3))
      y (quote (4 5 6))]
  (append (x y))) ) 

I'm receiving an

  clojure.lang.PersistentList cannot be cast to clojure.lang.IFn 

exception so I'm assuming that the list that I'm attempting to pass to the function is not of compatible type(like if I were to execute a list function, and try to pass that). I thought that quoting the list would make it accessible by interface functions. Can someone help me conceptualize how to abstract a list in order to manipulate its data in a separate function?

1 Answers

The source of error is this call:

(append(x y))

This expression doesn't call append with arguments x and y, but calls x with argument y and the result of this call is used as an argument for append.

But x is a list and list can't be used as a function- that's the meaning of clojure.lang.PersistentList cannot be cast to clojure.lang.IFn.

In Clojure, position of parentheses is very important and correct syntax for "call append with x and y" would be:

(append x y)

But there is much more to fix:

  • quote is usually shortened as ':
'(1 2 3)
=> (1 2 3)

But I suggest you to use vectors, like this:

[1 2 3]
=> [1 2 3]
  • You don't have to use two nested lets here, one let can have many bindings:
(let [x [1 2 3]
      y [4 5 6]]
  ...)
  • Cond with only two branches is if.
  • Don't use def inside defn- def creates a global variable. When you really need to create some variables inside function, use let.

Solution you're looking for looks like this:

(defn append [col1 col2]
  (if (empty? col1) 
    col2
    (cons (first col1)
          (append (rest col1) col2))))
                    
(let [x [1 2 3]
      y [4 5 6]]
  (append x y))
=> (1 2 3 4 5 6)

(There's an even more idiomatic version with seq, but empty? also works.)

Note that there's a function concat which does exactly the same thing.

Related