I often have to run my data through a function if the data fulfill certain criteria. Typically, both the function f
and the criteria checker pred
are parameterized to the data. For this reason, I find myself wishing for a higher-order if-then-else
which knows neither f
nor pred
.
For example, assume I want to add 10
to all even integers in (range 5)
. Instead of
(map #(if (even? %) (+ % 10) %) (range 5))
I would prefer to have a helper –let's call it fork
– and do this:
(map (fork even? #(+ % 10)) (range 5))
I could go ahead and implement fork
as function. It would look like this:
(defn fork
([pred thenf elsef]
#(if (pred %) (thenf %) (elsef %)))
([pred thenf]
(fork pred thenf identity)))
Can this be done by elegantly combining core
functions? Some nice chain of juxt
/ apply
/ some
maybe?
Alternatively, do you know any Clojure library which implements the above (or similar)?
As Alan Thompson mentions, cond->
is a fairly standard way of implicitly getting the "else" part to be "return the value unchanged" these days. It doesn't really address your hope of being higher-order, though. I have another reason to dislike cond->
: I think (and argued when cond->
was being invented) that it's a mistake for it to thread through each matching test, instead of just the first. It makes it impossible to use cond->
as an analogue to cond
.
If you agree with me, you might try flatland.useful.fn/fix
, or one of the other tools in that family, which we wrote years before cond->
1.
to-fix
is exactly your fork
, except that it can handle multiple clauses and accepts constants as well as functions (for example, maybe you want to add 10 to other even numbers but replace 0 with 20):
(map (to-fix zero? 20, even? #(+ % 10)) xs)
It's easy to replicate the behavior of cond->
using fix
, but not the other way around, which is why I argue that fix
was the better design choice.
1 Apparently we're just a couple weeks away from the 10-year anniversary of the final version of fix
. How time flies.