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 <[email protected]> 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 <[email protected]> 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 <[email protected]> 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 [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