我们如何基于函数简洁地定义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`)
是更好的,虽然不一定是巨大的利润率。事实上,显然comparing
早on
,我记得曾经看到有人争辩说,如果库被设计的今天,我们将不得不既不comparing
也不equating
,只是使用on
无处不在!但是:你的里程可能会有所不同:-)(我在这里保持中立。)