This is the second post in my „Did you know?“ series. This time we will
have a closer look at ->
and ->>
.
We all know the two threading forms which help a lot with chains of
calls. ->
threads on the first position, ->>
on the last. Here some
examples.
; This -> form
(-> a b (c d) (e f) g)
; expands to
(g (e (c (b a) d) f))
; And this ->> form
(->> a b (c d) (e f) g)
; expands to
(g (e f (c d (b a))))
Sometimes you have one or two one calls in the middle of the chain which require the other form. Then one has to split the chain.
(let [first-part (-> a b (c d))
second-part (->> first-part (map h) (filter pred))]
(-> second-part (e f) g))
However, we can actually simplify this!
(-> a
b (c d)
(->> (map f) (filter pred))
(e f) g)
Going the other way around is not so trivial. Trying the naive approach we get the following.
(->> x (map f) (-> (get :x)) (filter pred))
; expands to
(filter pred (map (get :x) f x))
Not quite what we want. The reason is, that ->>
inserts the expression
at the end of the next form. This is also the case for the contained
->
form. And from there on things go southwards.
However with a small trick, we can still get what we want: we simply
have to start with ->
.
(-> a
(->> (map h) (filter pred))
(c d) (e f)
(->> (remove second-pred) (reduce i)))
Here is a practical example (allthough a little stretched): a column index to Excel column converter.
user=> (def column-chars "ABCDEFGHIJKLMNOPQRSTUVWXYZ")
#'user/column-chars
user=> (defn index-to-column
[idx]
(->> idx
(iterate #(-> % dec (quot 26)))
(take-while (complement zero?))
(map #(-> % dec (rem 26) (->> (nth column-chars))))
reverse
(apply str)))
#'user/index-to-column
user=> (index-to-column 1)
"A"
user=> (index-to-column 26)
"Z"
user=> (index-to-column 27)
"AA"
user=> (index-to-column 677)
"ZA"
And finally – as a small teaser that there is more to explore – there is
also doto
. Consider this Swing example.
(doto (JFrame.)
(.setDefaultCloseOperation JFrame/DISPOSE_ON_CLOSE)
(-> .getContentPane (.add (JButton. "Hello")))
(.setVisible true))
There is a lot to explore in Clojure. Go on and experiment!
Published by Meikel Brandmeyer on .
I'm a long-time Clojure user and the developer of several open source projects mostly involving Clojure. I try to actively contribute to the Clojure community.
My most active projects are at the moment VimClojure, Clojuresque and ClojureCheck.
Copyright © 2009-2014 All Right Reserved. Meikel Brandmeyer