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
readability might be a concern but it's not the only criteria.
a) Do you need to trace intermediate results ? Then you need a
binding so you do not redo the work twice (presumably, I exclude memoized
functions here). Of course if the code has some side effects, the choice
is obvious, you do not want the tracing to redo the side effects twice...
b) Do you need to reference intermediate results in a closure ?
Then you need local bindings of course.
c) If a huge form becomes difficult to read then using local bindings will
enhance readability.
a) & b) might not be immediately obvious choices while writing the code.
They may arise later as you test/debug the code.
You may create bindings first to reflect logical chunks and then remove
them later if not needed.
I find it easier to add local bindings and removed when the code is stable
than vice-versa (but that could be an effect of aging, my brains maybe
getting slower along the way to terminal city :)))
Luc P.
Alan <al...@malloys.org> wrote ..
> --
> You received this message because you are subscribed to the Google
> Groups "Clojure" group.
> To post to this group, send email to clo...@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+u...@googlegroups.com
> For more options, visit this group at
> http://groups.google.com/group/clojure?hl=en
Thanks!
Dave
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.
The quoted section should perhaps be clarified with better
wording, but the example immediately following that quote still
accurately demonstrates the point we were trying to make:
(let [r (range 1e9)] [(first r) (last r)])
;=> [0 999999999]
(let [r (range 1e9)] [(last r) (first r)])
; java.lang.OutOfMemoryError: GC overhead limit exceeded
"Clojure's compiler can deduce that in the first example the
retention of `r` is no longer needed when the computation of
`(last r)` occurs and therefore aggressively clear it. However,
in the second example the head is needed later in the overall
computation and can no longer be safely cleared."
This is dramatically better than the "invisible" head-holding
that sometimes happened in earlier versions of Clojure (and was
noted in earlier versions of JoC), but is still good to be aware
of.
--Chouser
http://joyofclojure.com/