recur question

229 views
Skip to first unread message

michael

unread,
Oct 13, 2008, 4:03:22 AM10/13/08
to Clojure
Giving the factorial function as:

(def factorial
(fn [n] (cond (= n 1)
(> n 1) (* n (recur (dec n))))))

the compiler complains "Can only recur from tail position".
Isn't really the recur in tail position? It is the last expresson to
be evaluated.

Stuart Halloway

unread,
Oct 13, 2008, 8:12:19 AM10/13/08
to clo...@googlegroups.com
Hi Michael,

The multiplication by n comes after the recur.

Cheers,
Stuart

Stewart Griffin

unread,
Oct 13, 2008, 9:06:00 AM10/13/08
to clo...@googlegroups.com
2008/10/13 Stuart Halloway <stuart....@gmail.com>:

Hello,

Following on from what Stuart said, here is a version with recur that
uses an accumulator to avoid your problem:

(defn factorial
([n]
(factorial n 1))
([n acc]
(if (= n 0) acc
(recur (dec n) (* acc n)))))

Also, your method would return nil for (factorial 0), which should be
1, so I adjusted the termination condition to: (= n 0).

Regards,

Stewart Griffin

michael frericks

unread,
Oct 17, 2008, 2:47:46 AM10/17/08
to Clojure
Hi all,

thanks a lot for clarifying.

Regards,

Michael Frericks

Joel L

unread,
Oct 17, 2008, 12:43:59 PM10/17/08
to Clojure
This is interesting as I hit a similar stumbling block when I was
first playing with recur. I'm new to Lisp though not completely new to
functional programming, and have a style question about your solution:

Is there a particular reason you chose to arity overload the factorial
function rather than use the loop construct to include an
accumulator?

eg:
(defn factorial [n]
(loop ([acc 1, i n]
(if (= i 0) acc
(recur (dec i), (* acc i)))))

The reason I ask is I've always been a little bothered by having to
have a second 'accumulator version' of functions in functional
languages, especially since they're often meaningless out of context
(how can factorial take a second argument?) I really like loop..recur
because it allows the accumulator version to be hidden. Does that make
sense? Is there a general preference for the non-loop version?

I'm absolutely loving clojure by the way!

On Oct 13, 2:06 pm, "Stewart Griffin" <ste...@gmail.com> wrote:
> 2008/10/13 Stuart Halloway <stuart.hallo...@gmail.com>:

wwmorgan

unread,
Oct 17, 2008, 2:03:40 PM10/17/08
to Clojure
I think Stewart's code was more for exemplary purposes, to demonstrate
the use of recur in tail position. A more idiomatic approach might
look like this:

(defn factorial [n]
(apply * (range 1 (inc n))))
Reply all
Reply to author
Forward
0 new messages