By the way, http://tinyurl.com/2a235cn is an example of your style of
let being used in the Clojure source: the definition of defn itself.
It's a little overdone and weird-looking, but the alternative of
deeply nested forms would be much worse.

I didn't notice your question about technical tradeoffs the first
time, so I did a quick unscientific study:

(defmacro lets [n]
  (let [name (gensym)]
    `(let [~name 1
           ~@(interleave (repeat name)
                         (map (fn [_] (list '* 2 name))
                              (range n)))]
       ~name)))

(defmacro nested [n]
  (if-not (pos? n)
    1
    `(* 2 (lets ~(dec n)))))

I tested them both a few times on input sizes of 300, and neither one
was consistently faster (see below for why). For what it's worth, the
nested form blows the stack for large N (eg 400 in my case), while the
let form doesn't. I could write nested more carefully, probably using
iterate, so that it doesn't break during macroexpansion. I thought at
first that it would have to break eventually due to too many nested *
calls, but I was quite surprised to see that these two macros expand
to nearly identical things:

(clojure.pprint/pprint (clojure.walk/macroexpand-all '(lets 5)))
(let*
 [G__3255
  1
  G__3255
  (* 2 G__3255)
  G__3255
  (* 2 G__3255)
  G__3255
  (* 2 G__3255)
  G__3255
  (* 2 G__3255)
  G__3255
  (* 2 G__3255)]
 G__3255)

(clojure.pprint/pprint (clojure.walk/macroexpand-all '(nested 5)))
(clojure.core/*
 2
 (let*
  [G__3258
   1
   G__3258
   (* 2 G__3258)
   G__3258
   (* 2 G__3258)
   G__3258
   (* 2 G__3258)
   G__3258
   (* 2 G__3258)]
  G__3258))


On Oct 20, 9:52 am, Alan <a...@malloys.org> wrote:
> I agree with Tom (and with Stuart). I tend to like using ->> when it's
> convenient, since all you're really doing is performing a list of
> transformations on a single object. However, the let is better
> documentation if that's ever going to matter. Not because it makes it
> easier to understand what operations are being performed - ->> is just
> as good at that - but because you assign names to the intermediate
> results. Then someone reading your code can see what the purpose of
> each transformation is, without having to look at the definition of
> other functions.
>
> On Oct 19, 11:41 pm, Tom Faulhaber <tomfaulha...@gmail.com> wrote:
>
> > Dave,
>
> > Yes, this is perfectly idiomatic and many people in Clojure (and also
> > Haskell, for example) use let to help document how they're building up
> > their computation.
>
> > Stuart's suggestion is also good and it's largely a matter of personal
> > preference which to use when.
>
> > Of course, as you use clojure more, you'll probably become more
> > comfortable with more complex statements and not use the let style
> > quite so much.
>
> > Tom
>
> > On Oct 19, 8:19 pm, Dave Ray <dave...@gmail.com> wrote:
>
> > > Hey,
>
> > > I'm parsing a file with a chain of filter and map operations. To make
> > > it a little more readable (to me), I put the steps in a let like this:
>
> > > (defn parse-dictionary
> > >   [reader]
> > >   (let [lines    (read-lines reader)
> > >         trimmed  (map #(.trim %1) lines)
> > >         filtered (filter is-dictionary-entry? trimmed)]
> > >      (map parse-entry filtered)))
>
> > > Is this style of let considered good/bad stylistically? Are there
> > > technical tradeoffs between this and a bunch of nested forms?
>
> > > Thanks!
>
> > > Dave
>
>

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