On Aug 19, 10:01 pm, jon <superuser...@googlemail.com> wrote:
> Hi,
> Two problems I'd like to ask about.. (using clojure 1.0)
>
> (1) The following code seems to work correctly
> ( generates Hamming numbers -- 
> seehttp://en.wikipedia.org/wiki/Haskell_(programming_language)#More_comp...
> )
> but...
> ;--------------------------------------------------------------------
>  (defn merge-seqs [xs ys]
>     (lazy-seq
>       (let [x (first xs)  y (first ys)]
>         (cond (= x y) (cons x (merge-seqs (rest xs) (rest ys)))
>               (< x y) (cons x (merge-seqs (rest xs) ys))
>               :else   (cons y (merge-seqs xs (rest ys)))))))
>
>   (def hamming
>     (lazy-seq
>       (cons 1 (merge-seqs (map #(* 2 %) hamming) (merge-seqs (map #(*
> 3 %) hamming) (map #(* 5 %) hamming))))))
>
>   (prn (nth hamming 5000))
> ;--------------------------------------------------------------------
> ...if I define merge-seqs using destructured binding of the function
> arguments I get a java.lang.StackOverflowError.
> ;--------------------------------------------------------------------
>   (defn merge-seqs [[x & xs :as x-xs] [y & ys :as y-ys]]
>    (lazy-seq
>       (cond (= x y) (cons x (merge-seqs xs ys))
>             (< x y) (cons x (merge-seqs xs y-ys))
>             :else   (cons y (merge-seqs x-xs ys)))))
> ;--------------------------------------------------------------------
> Can that be avoided/fixed easily?
>

Right now destructuring's & uses next. There has been some discussion
about a variant (&& ?) that would use rest. So, right now, no, using
destructuring in this case has you requiring the future in order to
determine the present.

> (2) Here's a simplified function in a similar vein but using
> interleave for which the docs say "Returns a lazy seq" so I expected
> it to work.. however this also gives me a
> java.lang.StackOverflowError.
> ;--------------------------------------------------------------------
>   (def squares
>     (lazy-seq
>       (cons 1 (interleave (map #(* 2 %) squares) (map #(* 2 %)
> squares)))))
>
>   (prn (take 50 squares))
> ;--------------------------------------------------------------------
> If I replace the usage of interleave with the following hackish
> interleave2 that uses lazy-seq directly, it works as expected...
> ;--------------------------------------------------------------------
>   (defn interleave2 [& colls]
>     (lazy-seq
>       (when (not-any? nil? (map seq colls))
>         (concat (map first colls) (apply interleave2 (map rest
> colls))))))
>
>   (def squares
>     (lazy-seq
>       (cons 1 (interleave2 (map #(* 2 %) squares) (map #(* 2 %)
> squares)))))
>
>   (prn (take 50 squares))
> ;--------------------------------------------------------------------
> Is this a bug?

Yes, now fixed in master - thanks for the report.

> Is it because the call to apply in the original version breaks the
> laziness of concat?
>
> (defn interleave [& colls]
>     (apply concat (apply map list colls)))
>

Right, apply is (and always will be) mostly lazy, but ahead by one. It
needs to be because it must "spread" its last argument, and so must
know when it is at the last argument by lookahead.

> I haven't looked if there are any other api functions that should be
> lazy and fail in the same way?

Possibly mapcat, although it currently only promises to apply + apply.

Rich

--~--~---------~--~----~------------~-------~--~----~
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
-~----------~----~----~----~------~----~------~--~---

Reply via email to