Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 558
yurrriq Avatar asked Jul 31 '15 02:07

yurrriq


1 Answers

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.

like image 118
amalloy Avatar answered Nov 16 '22 16:11

amalloy