Search code examples
haskellclojurefunctional-programmingcombinators

In Clojure, is there a function like Haskell's on?


In Haskell, we have Data.Function.on:

on :: (b -> b -> c) -> (a -> b) -> a -> a -> c
(.*.) `on` f = \x y -> f x .*. f y

In Clojure, I want to be able to define, for example, an anagram predicate as follows:

(defn anagram? [word other-word]
  (and (not= word other-word)
       ((on = sort) word other-word)))

It's trivial to implement:

(defn on [g f] (fn [x y] (g (f x) (f y))))

But is there any built-in function that accomplishes the same goal? I can't seem to find one.


Solution

  • No, there is no built-in that does what you are looking for. If you are going to implement it, though, I think you can afford to be a little more generic, since Clojure has vararg support and lacks currying:

    (defn on
      ([f g]
         (fn [x y]
           (f (g x)
              (g y))))
      ([f g & args]
         (on f #(apply g % args))))
    

    This lets you write something like

    (defn same-parity? [x y]
      ((on = mod 2) x y))
    

    which of course is easy in Haskell too, as

    sameParity :: (Integral a) => a -> a -> Bool
    sameParity = (==) `on` (`mod` 2)
    

    But in Clojure the partial application of mod is a little trickier, so it's customary to provide equivalent functionality via &args if you can.