为了详细说明,通常可以为类型类实例函数提供默认实现,但是我想知道是否还可以为其他类型类的类型实例提供默认实现。
例如,假设我正在实现类型类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
函数。
答案 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建议非常有效。如果没有这种选择,您可以执行-
提供类似implXViaY
的方法,该方法通过X
为Y
提供了一种方法实现。例如,有时可以使用(<*>) = ap
形式的Applicative实例来完成此操作,其中ap
是基于Monad的>>=
的实现,或者是Functor的fmap = liftA
,其中{ {1}}基于Applicative中liftA
的实现。这不需要扩展。
提供一个Haskell模板函数,以在类型类有很多方法(基本上是1的扩展)的情况下自动使用默认定义。对于用户来说,类似(<*>)
。这要求客户端启用TemplateHaskell。