我们如何基于函数简洁地定义Eq?

问题描述:

我们可以用Data.Ord.comparing写出漂亮简洁Ord实例:我们如何基于函数简洁地定义Eq?

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的常用方法。显然这不是一个难以解决的问题,但是习惯用法是什么?

做到这一点的方法是复制你的equalityOn内联函数,使用Data.Function.on,其中有

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 -> Bool(更常见的名称为您equalityOn)的建议显然出现周期性的; here's an example thread from July 2014。普遍的共识似乎是(反复)((==) `on`)是更好的,虽然不一定是巨大的利润率。事实上,显然comparingon,我记得曾经看到有人争辩说,如果库被设计的今天,我们将不得不既不comparing也不equating,只是使用on无处不在!但是:你的里程可能会有所不同:-)(我在这里保持中立。)