覆盖派生类型类实例的默认实现
Override default implementations for derived typeclass instances
我定义了一个数据类型,我允许 GHC 为其自动派生 Eq typeclass
.
的实例
但是,派生实例并不具有我在所有情况下都需要的精确行为。
例如,查看此数据类型:
data IntegerOrFloat = I Integer | F Float
deriving Eq
(I 0) == (F 0)
的计算结果为 False
。我希望它评估为真。如果我正在编写实现,我可以简单地做:
instance Eq IntegerOrFloat where
(I i) == (F f) = (fromIntegral i) == f
但是,我将不得不写其他三个案例。显然这对于这种类型来说是微不足道的,但这是一个人为的例子。我非常喜欢让大多数情况自动派生的便利。
有没有一种方法可以让我“覆盖”特定案例的派生实现,而不必手动编写整个实现?
您可以使用 generic-deriving
package [Hackage],这会为属于 Generic
类型 class:
的类型实现
{-# LANGUAGE <b>DeriveGeneric</b> #-}
import Generics.Deriving.Base(Generic)
import Generics.Deriving.Eq(GEq, geq)
data IntegerOrFloat = I Integer | F Float
deriving (<b>Generic</b>)
instance GEq IntegerOrFloat
instance Eq IntegerOrFloat where
F f == I i = fromIntegral i == f
I i == F f = fromIntegral i == f
x == y = geq x y
因此,geq :: GEq a => a -> a -> Bool
是一个自动生成 (==)
函数的实例,就像 Haskell 那样,然后我们可以使用 geq
this 作为基函数。
您可以按原样保留派生类型,但仅导出覆盖了特殊情况的新类型包装版本:
data IntegerOrFloat' = I' Integer | F' Float
deriving Eq
newtype IntegerOrFloat = IOF { getIOF :: IntegerOrFloat' }
instance Eq IntegerOrFloat where
IOF (I i) == IOF (F f) = fromIntegral i == f
IOF (F f) == IOF (I i) = f == fromIntegral i
IOF x == IOF y = x==y
但我真的觉得这很可疑。如果您需要不同的 Eq
行为,那么您可能应该完全手动实现所有内容 – 不同的 Eq
实例意味着几乎所有内容都应该将 F 0
和 I 0
视为相同的值,这不是编译器对派生实例的假设。
我定义了一个数据类型,我允许 GHC 为其自动派生 Eq typeclass
.
但是,派生实例并不具有我在所有情况下都需要的精确行为。
例如,查看此数据类型:
data IntegerOrFloat = I Integer | F Float
deriving Eq
(I 0) == (F 0)
的计算结果为 False
。我希望它评估为真。如果我正在编写实现,我可以简单地做:
instance Eq IntegerOrFloat where
(I i) == (F f) = (fromIntegral i) == f
但是,我将不得不写其他三个案例。显然这对于这种类型来说是微不足道的,但这是一个人为的例子。我非常喜欢让大多数情况自动派生的便利。
有没有一种方法可以让我“覆盖”特定案例的派生实现,而不必手动编写整个实现?
您可以使用 generic-deriving
package [Hackage],这会为属于 Generic
类型 class:
{-# LANGUAGE <b>DeriveGeneric</b> #-}
import Generics.Deriving.Base(Generic)
import Generics.Deriving.Eq(GEq, geq)
data IntegerOrFloat = I Integer | F Float
deriving (<b>Generic</b>)
instance GEq IntegerOrFloat
instance Eq IntegerOrFloat where
F f == I i = fromIntegral i == f
I i == F f = fromIntegral i == f
x == y = geq x y
因此,geq :: GEq a => a -> a -> Bool
是一个自动生成 (==)
函数的实例,就像 Haskell 那样,然后我们可以使用 geq
this 作为基函数。
您可以按原样保留派生类型,但仅导出覆盖了特殊情况的新类型包装版本:
data IntegerOrFloat' = I' Integer | F' Float
deriving Eq
newtype IntegerOrFloat = IOF { getIOF :: IntegerOrFloat' }
instance Eq IntegerOrFloat where
IOF (I i) == IOF (F f) = fromIntegral i == f
IOF (F f) == IOF (I i) = f == fromIntegral i
IOF x == IOF y = x==y
但我真的觉得这很可疑。如果您需要不同的 Eq
行为,那么您可能应该完全手动实现所有内容 – 不同的 Eq
实例意味着几乎所有内容都应该将 F 0
和 I 0
视为相同的值,这不是编译器对派生实例的假设。