> I know that the JVM does not offer tail-call optimization, but is
> there a way to rewrite the example (perhaps with (recur ...)) so that
> (nth fib-seq N) runs in constant space?
>
Turning the seq into a fn will allow it to be reclaimed and thus the
computation will run in constant space.
(defn fib-seq[]
(concat
[0 1]
((fn rfib [a b]
(lazy-cons (+ a b) (rfib b (+ a b)))) 0 1)))
(let [r (nth (fib-seq) 100000)] r)
(The let is here to prevent the Repl to retain the sequence -- I don't know why teh Repl keeps a reference to the computed value of the arg.)
Christophe
Christophe
Hi Clojurians,
> (defn fib-seq []
> ((fn rfib [a b]
> (lazy-cons a (rfib b (+ a b))))
> 0 1))
Can be roughly translated to Haskell as:
fix f = f (fix f)
fibs = 0 : 1 : fix (\rfib a b -> a+b : rfib b (a+b)) 0 1
Well, this function also eats up memory - my computer can't get to the
50000th number neither in Closure nor GHCi. GHCi could get there but
not much further with this slightly more Haskellish version:
fibs = 0 : 1 : [ a + b | (a, b) <- fibs `zip` tail fibs ]
It think this has nothing to do with the excellent Clojure
implementation - just with the fact that it takes a lot of memory to
handle numbers in the 1.68^100K range.
As to
> (defn fib-seq []
> ((fn rfib [a b]
> (lazy-cons a (rfib b (+ a b))))
> 0 1))
This is more concise but it isn't it "cheating" in that fib-seq is a
function, not a lazy sequence? :)
Sorry for not being clear, the "cheating" part is a very minor
complaint of mine, that fibs-seq is a function type, e.g. you can't
(nth 10000 fib-seq) but rather (nth 10000 (fib-seq)). This is easily
fixed:
(def fibs (fibs-seq))
Sorry for nitpicking.