On Wed, Jul 29, 2009 at 2:59 AM, Daniel Lyons <[email protected]>wrote:

> Probably it would help to try and implement a lazy
> list of the Fibonacci sequence before looking at that code, and then
> maybe try some other mathematical sequences that are a little easier
> to construct too.
>

Using the super-lazy-seq macro Wrexsoul posted a month or so ago, that's
dead easy:

(super-lazy-seq [a 0 b 1] (next-item b b (+ a b)))

On the other hand,

(defn fibs [] (cons 1 (cons 1 (lazy-seq (map + (fibs) (rest (fibs)))))))
(def fibs (memoize fibs))

works and is done with map rather than a looping-like construct. (Without
the memoize, the latter is exponential in time; with it, though, all
generated terms are retained in memory. This could be scoped, by using
(binding [fibs (memoize fibs)] (take n fibs)) or whatever whenever you
needed to do something with (part of) fibs, and returning something.
Downside: binding doesn't work well with lazy seqs. It's actually probably
easier to use the first version efficiently in a pure-functional way, even
if its less pure-functional "inside". On the other hand, I'm a bit
suspicious of that macro. It seems to work for common cases, but I suspect
it will not work properly if you shadow one of its loop bindings with a let
in the loop body, as I think it doesn't care if it's the same var so long as
it has the same name when it wraps the loop vars in a deref.

(map second (iterate (fn [[a b]] [b (+ a b)]) [0 1]))

seems to work though and avoids the memory problems of the memoized
function, the exponential tendencies of the un-memoized function, AND the
super-lazy-seq macro (and even the lazy-seq macro). Interestingly, it works
identically to the super-lazy-seq macro in that both start with a pair of [a
= 0, b = 1] and transform it according to [a -> b, b -> (+ a b)].

In fact, there's a general correspondence between
(map #(nth % n) (iterate (fn [[a b c ... z]] [exprs]) [a0 b0 c0 ... z0]))
and
(super-lazy-seq [a a0 b b0 c c0 ... z z0] (next-item an exprs))
and I suspect the map/iterate versions to be more efficient since they avoid
atoms. (On the other hand, if the sequence is generated in a non-functional
way, such as from network I/O, super-lazy-seq seems to me to be a better fit
as long as you avoid shadowing any of its loop bindings internally.)

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to [email protected]
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to