是否可以为我的 class Y 类型提供某种类型 class X 的默认实例?
Is it possible to provide default instances of some type class X for my type class Y?
详细来说,通常可以为 class 类型的实例函数提供默认实现,但我想知道是否也可以为 class 类型的其他类型的实例提供默认实现 classes。
例如,假设我正在实现类型 class Y
并且我希望 Y
的所有实例 a
满足其他一些 X a
输入 class X
。最初我试图通过写 instance Y a => X a where ...
来做到这一点,但发现这实际上是不可能的 (Haskell Constraint is no smaller than the instance head)。但是,与另一个问题中描述的更一般的情况不同,可能有不止一种类型 class 约束,我的情况下只有一个 class 约束,所以我认为可能有一种在 class 定义级别执行此操作的方法,可能使用 Haskell 语言扩展。
另一个问题中描述的方法似乎不太顺利 - 假设 X
实际上是 Ord
。由某些 newtype
包装 Ord
可防止在原始类型上直接使用 Ord
函数。
这里常用的技巧是用你想要的实例定义一个 newtype
包装器。有关此示例,请参见 WrappedMonoid
。在你的情况下:
newtype WrappedY a = WrapY { unwrapY :: a }
instance Y a => X (WrappedY a) where
-- your default implementation here
然后,具有 Y
实例的类型可以使用新的 DerivingVia
扩展派生其 X
实例。
{-# LANGUAGE DerivingVia #-}
data SomeType = ...
deriving X via WrappedY SomeType
instance Y SomeType where
-- your implementation here
如果您的用户有可用的 GHC 8.6+(DerivingVia
是一个相当新的扩展),Alec 的回答中的 newtype wrapper + DerivingVia 建议效果很好。如果这不是一个选项,您可以执行类似 -
的操作
提供类似implXViaY
的方法,它通过Y
为X
提供方法实现。例如,这有时使用 (<*>) = ap
形式的 Applicative 实例来完成,其中 ap
基于 Monad 的 >>=
的实现,或者使用具有 fmap = liftA
的 Functor,其中 liftA
是基于Applicative中(<*>)
的实现。这不需要扩展。
提供一个模板Haskell函数来自动使用默认定义,以防类型class有很多方法(这基本上是1的扩展)。所以像 makeXviaY ''MyType
这样的用户。这需要客户端启用TemplateHaskell.
详细来说,通常可以为 class 类型的实例函数提供默认实现,但我想知道是否也可以为 class 类型的其他类型的实例提供默认实现 classes。
例如,假设我正在实现类型 class Y
并且我希望 Y
的所有实例 a
满足其他一些 X a
输入 class X
。最初我试图通过写 instance Y a => X a where ...
来做到这一点,但发现这实际上是不可能的 (Haskell Constraint is no smaller than the instance head)。但是,与另一个问题中描述的更一般的情况不同,可能有不止一种类型 class 约束,我的情况下只有一个 class 约束,所以我认为可能有一种在 class 定义级别执行此操作的方法,可能使用 Haskell 语言扩展。
另一个问题中描述的方法似乎不太顺利 - 假设 X
实际上是 Ord
。由某些 newtype
包装 Ord
可防止在原始类型上直接使用 Ord
函数。
这里常用的技巧是用你想要的实例定义一个 newtype
包装器。有关此示例,请参见 WrappedMonoid
。在你的情况下:
newtype WrappedY a = WrapY { unwrapY :: a }
instance Y a => X (WrappedY a) where
-- your default implementation here
然后,具有 Y
实例的类型可以使用新的 DerivingVia
扩展派生其 X
实例。
{-# LANGUAGE DerivingVia #-}
data SomeType = ...
deriving X via WrappedY SomeType
instance Y SomeType where
-- your implementation here
如果您的用户有可用的 GHC 8.6+(DerivingVia
是一个相当新的扩展),Alec 的回答中的 newtype wrapper + DerivingVia 建议效果很好。如果这不是一个选项,您可以执行类似 -
提供类似
implXViaY
的方法,它通过Y
为X
提供方法实现。例如,这有时使用(<*>) = ap
形式的 Applicative 实例来完成,其中ap
基于 Monad 的>>=
的实现,或者使用具有fmap = liftA
的 Functor,其中liftA
是基于Applicative中(<*>)
的实现。这不需要扩展。提供一个模板Haskell函数来自动使用默认定义,以防类型class有很多方法(这基本上是1的扩展)。所以像
makeXviaY ''MyType
这样的用户。这需要客户端启用TemplateHaskell.