Thanks Meikel for such an insightfull feedback. Its hard to imagine so much
thought goes into writing trivial looking functions.
Sunil.

On Thu, Nov 25, 2010 at 1:00 PM, Meikel Brandmeyer <m...@kotka.de> wrote:

> Hi,
>
> On 25 Nov., 05:06, Sunil S Nandihalli <sunil.nandiha...@gmail.com>
> wrote:
>
> > (defn every-nth [n coll]
> >   (letfn [(evn [cn s]
> >             (when s
> >               (if (= cn 1)
> >                 (lazy-seq (cons (first s) (evn n (next s))))
> >                 (evn (dec cn) (next s)))))]
> >     (evn n coll)))
>
> Since you want to learn how lazy-seq works here some feedback.
>
> * Make the lazy-seq the outer-most part of your function
>  to allow as much laziness as possible. There other
>  opinions out there about the placement of lazy-seq, but
>  there are also a lot of people complaining about eg. a
>  filter doing an expensive predicate call because the
>  input sequence is not as lazy as it could be. By placing
>  lazy-seq outermost you leave the decision to them when
>  to realize an element.
>
> * You should call seq on coll before passing it to evn.
>  Think of [] as input. It will be truthy in the when check
>  and we do some unnecessary loop, where we actually could
>  short circuit.
>
> * Don't call next in the true branch of the if. It realises
>  an element of the input sequence where it is not
>  necessary. Use rest.
>
> * Don't call evn in the false branch of the if. It will be
>  true recursion and might blow the stack for large n. You
>  Use recur.
>
> Here is the version I would write in this case.
>
> (defn every-nth
>  [n coll]
>   (let [step (fn step [s]
>               (lazy-seq
>                 (loop [s   (seq s)
>                        cnt n]
>                   (when s
>                     (if (= cnt 1)
>                       (cons (first s) (step (rest s)))
>                       (recur (next s) (dec cnt)))))))]
>    (step coll)))
>
> * lazy-seq is outer-most.
> * The recur is turned into a loop to avoid stacking lazy-seq
>  on lazy-seq.
> * The input sequence is only realised inside the lazy-seq.
>  Also in the true branch we use rest to defer realisation
>  of the next seq step. In the false branch we use next,
>  because we need the value anyway.
>
> As a rule of thumb: write your generating function with
> "normal" recursion first. Then simply wrap a lazy-seq
> around it.
>
> Hope that helps.
>
> Sincerely
> Meikel
>
> --
> 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<clojure%2bunsubscr...@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 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