On 12 April 2016 at 14:58, Cornelius Goh <cornelius...@gmail.com> wrote:

> True. Clojure doesn't provide tail call optimization. According to Daniel
> Higginbotham  book "Clojure for the Brave and True" (Page 102) he suggests
> using "recur" for performance reasons.
>
> That is, in Olivier's original code, (sorry, without understanding his
> puzzle):
>
>
> (defn  permutations [s]
>    (lazy-seq
>    ...
>    ...
>               (map # (...) (recur (remove #...)))))
>     ...
>
> See if it improves performance by just using "recur" ?


But you can't do that, because you're using the return value there
(specifically, as the argument to map). If you try it, you'll see that the
compiler throws an error.

The idea behind tail call elimination is that, if the very last thing that
your function, say fnA, does is returning the result of a call to another
function, say fnB, then you do not need the stack frame of fnA during the
call to fnB, and you can preemptively pop it before calling fnB. But this
only works if calling fnB is the very last thing that fnA does: if fnA
still has some work to do with the result of fnB, its stack cannot be
destroyed. (You could argue that a sufficiently smart compiler could "trim"
the stack to just what will be needed after the call to fnB, but it's not
the same.)

A simple, well-known example is the case of the recursive factorial
function:

(defn non-tce-fact
  [n]
  (if (zero? n)
    1
    (* n (non-tce-fact (dec n)))))
(defn tce-fact
  ([n] (tce-fact n 1))
  ([n p]
    (if (zero? n)
      p
      (recur (dec n) (* n p)))))


Note that in the first function, the result of the recursive call is used
in the multiplication, whereas in the second function the result is
directly the result of the recursive call.

Most common examples are of recursive functions, but TCE is (in principle)
a general technique that can be applied to any function whose last
instruction is a call to another function.

In Clojure, only recursive tail call elimination is supported, and only
when the programmer explicitly requires it by using recur instead of an
explicit recursive call. This has the advantage (and disadvantage) of being
explicit and checked by the compiler (i.e. if you use recur in a non-tail
position, you get an error).

-- 
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
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to