我们可以使用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
的常用方法。显然这不是一个难以解决的问题,但是惯用法是什么?
答案 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 -> Bool
(equalityOn
的更常见名称)的提案显然会定期出现; here's an example thread from July 2014。普遍的共识似乎是(反复地)((==) `on`)
是优选的,尽管不一定是一个巨大的差距。事实上,显然comparing
早于on
,我记得曾经有人认为如果图书馆是今天设计的,我们就不会 comparing
或{{1到处都只使用equating
!但是:你的里程可能会有所不同:-)(我在这里保持中立。)