在Clojure中,是否有类似Haskell的on函数?

11
在 Haskell 中,我们有Data.Function.on: Data.Function.on
on :: (b -> b -> c) -> (a -> b) -> a -> a -> c
(.*.) `on` f = \x y -> f x .*. f y
在Clojure中,我希望能够像下面这样定义一个字谜谓词:
(defn anagram? [word other-word]
  (and (not= word other-word)
       ((on = sort) word other-word)))

它很容易实现:

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

但是有没有内置函数能够实现相同的目标呢?我似乎找不到。


4
也许 (defn on [g f] #(apply g (map f %&))) 是Clojure中支持变长参数的精神。 - noisesmith
1个回答

4

不,没有内置的功能可以做到你想要的。但如果你要实现它,我认为你可以更加通用,因为Clojure支持可变参数而且缺少柯里化:

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

这使得您可以编写类似于:

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

当然,在Haskell中也很容易实现,就像这样:
sameParity :: (Integral a) => a -> a -> Bool
sameParity = (==) `on` (`mod` 2)

但在Clojure中,对mod函数进行部分应用有一点棘手,因此如果可能的话,通常会通过&args提供等效功能。


on的可变参数版本让我感到不适... 我是否正确理解 ((on = mod 2) x y) 等同于 (= (mod x 2) (mod y 2))?我喜欢Haskell版本,因为(mod 2)明确了参数的顺序,但在Clojure中,我本来期望是(mod 2 x)而不是(mod x 2) - yurrriq
1
@EricBailey 抱歉,我贴的是一个缺少(fn [x y])的旧版本。至于可变参数的顺序,我的确是与其他部分应用函数相适应的顺序。例如比较 (swap! x / 10):它被转换为 (swap! x #(/ % 10)),而不是 (swap! x #(/ 10 %))。如果你习惯了 Haskell,这个顺序可能看起来不自然,但这个顺序比另一种顺序更常用。 - amalloy
转念一想,(mod x 2) 在Clojure中更有意义,我只是不想使用varargs版本。 - yurrriq
1
无论如何,您已经回答了我的问题并给了我一些思考的食粮。谢谢! - yurrriq

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接