A collection of Clojure macros that complement the clojure.core
threading macros ->
and ->>
.
To start, create a Leiningen project and add the following dependency to project.clj
:
Next, load the macros as follows:
(require '[fletching.macros :refer :all])
The macro
>>
removes itself from the head of the enclosing S-expression, and then moves the second form in the remaining expression to the end of the expression.
Intended to be used within ->
to switch to ->>
conventions.
(-> [[1 2 3] [3 4 5]]
(nth 1)
(->> (map -))
(nth 1))
;=> -4
This can be rewritten as
(-> [[1 2 3] [3 4 5]]
(nth 1)
(>> map -)
(nth 1))
;=> -4
The macro
<<
removes itself from the head of the enclosing S-expression, and then moves the last form in the expression to the second position.
This macro addresses the problem of nesting ->
within ->>
.
Working around this composition problem using clojure.core
macros was already possible, but not always very elegant. You might have been writing code like this:
(-> (->> [-1 -2 -3 -4 -5]
(map -)
(filter even?))
last
range
rest
(->> (reduce *)))
;=> 6
Or like this:
(as-> [-1 -2 -3 -4 -5] x
(map - x)
(filter even? x)
(-> x last range rest)
(reduce * x))
;=> 6
Now you can write this:
(->> [-1 -2 -3 -4 -5]
(map -)
(filter even?)
(<< -> last range rest)
(reduce *))
;=> 6
Of course, <<
is also useful in one-off situations:
(->> [1 2 3 4 5]
(map -)
(<< nth 2)
(/ 6))
;=> -2
The macros
?>
and<?
remove themselves from the head of the enclosing S-expression, and then remove the second (?>
) or last (<?
) form in the remaining expression and bind it to?
.
These macros are useful when you're composing functions using ->
or ->>
and you find yourself needing a little bit more flexibility for some of the threaded expressions.
(->> [1 2 3 4 5]
(take 3)
(reduce *)
(<? str ? " is " (if (even? ?) "even" "odd"))
(<? do [? ?]))
;=> ["6 is even" "6 is even"]
The macro
><
removes itself from the head of the enclosing S-expression.
This macro is useful when you want to thread functions (as opposed to function arguments):
(-> [+ - * /]
(nth 2)
(>< 3 4)
inc)
;=> 13
Equivalently,
(->> [+ - * /]
(drop 2)
first
(<< >< 3 4)
inc)
;=> 13
The macros
<fn
and<&fn
remove themselves from the head of the enclosing S-expression, and then insert a variable in the second position of the remaining expression. Finally, the expression is transformed into a 1-ary (<fn
) or variadic (<&fn
) lambda, which binds the variable.
<fn
and <&fn
can be used for defining functions in a point-free style:
(def f (<fn ->> (map -)
(filter even?)
(reduce *)))
(f [2 4 5 6])
;=> -48
<&fn
is like <fn
but takes a variable number of arguments, which it threads into the expression as a sequence.
(def g (<&fn ->> (map -)
(filter even?)
(reduce *)))
(g 2 4 5 6)
;=> -48
Copyright © 2015 Jonas De Vuyst
Distributed under the Eclipse Public License either version 1.0 or (at your option) any later version.