HB <hubaghd...@gmail.com> writes: > I'm trying to write a function that calculates the length of a list: > > (defn list-length [col] > (if col > (+ 1 (list-length(rest col))) > 0)) > > > (list-length '(Java, Clojure, Scala)) > > Upon running it in the REPL, I got the error: > java.lang.StackOverflowError (test.clj:3) > > What is going wrong?
In Clojure (unlike many other lisps) the empty list (), nil and false are different things. The empty list is "truthy". Try this instead: (defn list-length [coll] (if-let [s (seq coll)] (+ 1 (list-length (rest s))) 0)) The seq function will return nil on an empty sequence. It's also good form to capture its output as s, so that if you pass in something that's not a sequence, for example a hash-map, then it doesn't have to be converted to a seq twice. The above will still blow up with a StackOverflowError on very large lists because it is not tail-recursive. We can transform it into a tail-recursive form by passing the count-so-far as an optional argument (initialized to 0) and using recur for the recursive call: (defn list-length ([coll] (list-length coll 0)) ([coll n] (if-let [s (seq coll)] (recur (rest s) (inc n)) n))) That's of course a really common pattern that comes up all the time. So Clojure provides a higher-level function (reduce) that does the iteration and recursion for you. So a nicer implementation might be: (defn list-length [coll] (reduce (fn [n x] (inc n)) 0 coll)) Of course in practice you should just use the built-in count function (which is O(1) on most data structures) but I assume this is an exercise. :-) If you're interested in the history behind the decision to make the empty list truthy, have a look here: http://clojure.org/lazy In very early (pre 1.0) versions of Clojure your function would have actually worked as you expected. The change from the Common Lisp model was made to allow for "fully" lazy sequences. -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en