Armand
Armand

Reputation: 24393

Correct use of `recur` in Clojure?

I'm trying to solve the Count a Sequence problem on 4Clojure, but I can't work out what's wrong with my use of recur:

fn [s] (
    fn [t n] (
        if (empty t)
            n
            (recur (rest t) (+ n 1))
    ) s 0
)

It gives the following exception:

java.lang.UnsupportedOperationException: Can only recur from tail position, compiling:(NO_SOURCE_PATH:0)

But to me it seems that the call to recur is in a tail position for the inner function. What am I missing?

Upvotes: 1

Views: 287

Answers (2)

Dave Yarwood
Dave Yarwood

Reputation: 3010

@Thumbnail is right -- your code will work just fine if you fix the placement of your parentheses (most importantly, you need to add a ( before (fn [t n] ... and a corresponding ) after s 0, in order to actually return the result of calling that function (the one that takes t and n as arguments) on the values s and 0. Otherwise, you are returning the function itself.), and change empty to empty?.

If you wanted to simplify things a bit, you might consider using a loop/recur structure instead, like this:

(fn [s]
  (loop [t s, n 0]
    (if (empty? t)
      n
      (recur (rest t) (+ n 1)))))

Upvotes: 3

Thumbnail
Thumbnail

Reputation: 13483

Two problems:

  • Your parentheses are misplaced.
  • You are using empty where you want empty?.

Parentheses

  • The fn special form for defining a function takes the shape (fn name? [params* ] exprs*) with the parentheses around it.
  • Another level of parentheses applies the function ((fn [n] (* n n)) 3) => 9.

Using defn instead of fn for the moment, we get

(defn l [s] 
  ((fn [t n] (if (empty? t) n (recur (rest t) (+ n 1))))
       s 0))

Then, for example,

(l ())
; 0

and

(l [1 2 3])
; 3

Upvotes: 3

Related Questions