是否可以为我的 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 建议效果很好。如果这不是一个选项,您可以执行类似 -

的操作
  1. 提供类似implXViaY的方法,它通过YX提供方法实现。例如,这有时使用 (<*>) = ap 形式的 Applicative 实例来完成,其中 ap 基于 Monad 的 >>= 的实现,或者使用具有 fmap = liftA 的 Functor,其中 liftA是基于Applicative中(<*>)的实现。这不需要扩展。

  2. 提供一个模板Haskell函数来自动使用默认定义,以防类型class有很多方法(这基本上是1的扩展)。所以像 makeXviaY ''MyType 这样的用户。这需要客户端启用TemplateHaskell.