是否可以为类型I提供某些类型X的默认实例?

时间:2019-01-27 20:52:48

标签: haskell

为了详细说明,通常可以为类型类实例函数提供默认实现,但是我想知道是否还可以为其他类型类的类型实例提供默认实现。

例如,假设我正在实现类型类http://<myproject>.firebaseapp.com,并且我希望Y的所有实例a满足其他一些类型类{{1}的Y }。最初,我试图通过编写X a来做到这一点,但是看到这实际上是不可能的(Haskell Constraint is no smaller than the instance head)。但是,与在另一个问题中描述的更一般的情况不同,在这种情况下可能存在多个类型类约束,而在我的情况下,我只有一个类约束,因此我认为在类上可能有一种方法定义级别,可能使用Haskell语言扩展。

在另一个问题中描述的方法似乎不太顺利-假设X实际上是instance Y a => X a where ...。用某些X包装Ord可以防止直接在原始类型上使用Ord函数。

2 个答案:

答案 0 :(得分:9)

通常的技巧是使用所需的实例定义一个newtype包装器。有关此示例,请参见WrappedMonoid。就您而言:

newtype WrappedY a = WrapY { unwrapY :: a }

instance Y a => X (WrappedY a) where 
  -- your default implementation here

然后,具有Y实例的类型可以使用新的X扩展名派生其DerivingVia实例。

{-# LANGUAGE DerivingVia #-}

data SomeType = ...
  deriving X via WrappedY SomeType

instance Y SomeType where
  -- your implementation here

答案 1 :(得分:4)

如果您的用户拥有可用的GHC 8.6 +(DerivingVia是一个相当新的扩展),则Alec答案中的新型包装+ DerivingVia建议非常有效。如果没有这种选择,您可以执行-

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

  2. 提供一个Haskell模板函数,以在类型类有很多方法(基本上是1的扩展)的情况下自动使用默认定义。对于用户来说,类似(<*>)。这要求客户端启用TemplateHaskell。