我们如何根据函数简洁地定义Eq?

时间:2016-02-27 06:47:42

标签: haskell

我们可以使用Data.Ord.comparing编写非常简洁的Ord个实例:

comparing :: Ord a => (b -> a) -> b -> b -> Ordering
comparing p x y = compare (p x) (p y)

f :: b -> a

instance Ord a => Ord b where compare = comparing f

我希望找到一些有助于定义Eq个实例的类似函数:

-- Does something like this exist?
equalityOn :: Eq a => (b -> a) -> b -> b -> Bool
equalityOn p a b = p a == p b

instance Eq a => Eq b where (==) = equalityOn f

Hoogle没有使用此签名发现任何内容,所以我猜这不是定义Eq的常用方法。显然这不是一个难以解决的问题,但是惯用法是什么?

1 个答案:

答案 0 :(得分:9)

这样做的方法是使用Data.Function.on重新生成equalityOn函数,其类型为

on :: (b -> b -> c) -> (a -> b) -> a -> a -> c

此功能概括了comparing

(.*.) `on` f = \x y -> f x .*. f y

(来自基地的literally the implementation)。因此,我们有comparing = (compare `on`); on通过将任何二元函数应用于一元函数的结果来提升它。

所以equalityOn只是((==) `on`),您的示例实例变为

import Data.Function

instance Eq A => Eq B where
  (==) = (==) `on` f

添加equating :: Eq a => (b -> a) -> b -> b -> BoolequalityOn的更常见名称)的提案显然会定期出现; here's an example thread from July 2014。普遍的共识似乎是(反复地)((==) `on`)是优选的,尽管不一定是一个巨大的差距。事实上,显然comparing早于on,我记得曾经有人认为如果图书馆是今天设计的,我们就不会 comparing或{{1到处都只使用equating!但是:你的里程可能会有所不同:-)(我在这里保持中立。)