Given a ->>
pipeline like so:
(defn my-fn []
(->> (get-data)
(do-foo)
(do-bar)
(do-baz)))
I wish to make the various stages conditional.
The first way of writing this that came to mind was as such:
(defn my-fn [{:keys [foo bar baz]}]
(->> (get-data)
(if foo (do-foo) identity)
(if bar (do-bar) identity)
(if baz (do-baz) identity))
However, as the ->>
macro attempts to insert into the if
form, this not only looks unfortunate in terms of performance (having the noop identity
calls), but actually fails to compile.
What would an appropriate, reasonably DRY way of writing this be?
Modern Clojure (that is, as of 1.5) supports a variety of options for conditional threading, but you probably want cond->>
.
cond->
and cond->>
Clojure offers cond->
and cond->>
, which each ask for a set of pairs: a test and an expression if that test evaluates to true. These are quite similar to cond
but don't stop at the first true test.
(cond->> 5
true inc
false inc
nil inc)
=> 6
Your specific example is probably best written like so:
(defn my-fn [{:keys [foo bar baz]}]
(cond->> (get-data)
foo (do-foo)
bar (do-bar)
baz (do-baz)))
It's worth mentioning as->
because it is perhaps the most versatile threading macro. It gives you a name to refer to the "thing" being threaded through the forms. For instance:
(as-> 0 n
(inc n)
(if false
(inc n)
n))
=> 1
(as-> 0 n
(inc n)
(if true
(inc n)
n))
=> 2
This gives substantial flexibility when working with a mix of functions that require threading the expression at different points in the parameter list (that is, switching from -> to ->> syntax). One should avoid the use of extraneous named variables in the interest of code readability, but oftentimes this is the clearest and simplest way to express a process.
This works too:
(defn my-fn [{:keys [foo bar baz]}]
(->> (get-data)
(#(if foo (do-foo %) %))
(#(if bar (do-bar %) %))
(#(if baz (do-baz %) %)) ))
You might be interested in these macros https://github.com/pallet/thread-expr
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With