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 dislikecond->: I think (and argued whencond->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 usecond->as an analogue tocond.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 beforecond->1.to-fixis exactly yourfork, 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):It's easy to replicate the behavior of
cond->usingfix, but not the other way around, which is why I argue thatfixwas 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.