我想定义一个具有两个方法的类型类,在其中实现任何一个方法就足够了(但是如果需要,您可以独立地实现两个方法)。这种情况与Eq
和x == y = not (x /= y)
中的x /= y = not (x == y)
相同。到目前为止,我可以做的完全一样:
class (FunctorB b) => DistributiveB (b :: (Type -> Type) -> Type) where
bdistribute :: (Distributive f) => f (b g) -> b (Compose f g)
bdistribute x = bmap (\f -> Compose $ fmap f . bsequence' <$> x) bshape
bshape :: b ((->) (b Identity))
bshape = bdistribute' id
bdistribute' :: (DistributiveB b, Distributive f) => f (b Identity) -> b f
bdistribute' = bmap (fmap runIdentity . getCompose) . bdistribute
但是,我还想提供bdistribute
的通用 default 实现,如果bdistribute
没有定义,我可以这样做:
class (FunctorB b) => DistributiveB (b :: (Type -> Type) -> Type) where
bdistribute :: (Distributive f) => f (b g) -> b (Compose f g)
default bdistribute
:: forall f g
. CanDeriveDistributiveB b f g
=> (Distributive f) => f (b g) -> b (Compose f g)
bdistribute = gbdistributeDefault
bshape :: b ((->) (b Identity))
bshape = bdistribute' id
但是,一旦我想两者都做,它就会中断:
class (FunctorB b) => DistributiveB (b :: (Type -> Type) -> Type) where
bdistribute :: (Distributive f) => f (b g) -> b (Compose f g)
bdistribute x = bmap (\f -> Compose $ fmap f . bsequence' <$> x) bshape
default bdistribute
:: forall f g
. CanDeriveDistributiveB b f g
=> (Distributive f) => f (b g) -> b (Compose f g)
bdistribute = gbdistributeDefault
bshape :: b ((->) (b Identity))
bshape = bdistribute' id
,并显示以下错误消息:
bdistribute
的定义冲突
现在,我可以看到此错误的含义了;而且,我认为我想要的也是合理且定义明确的:如果您手写DistributiveB
实例,则可以覆盖bdistribute
和/或bshape
,但是如果您只需编写instance DistributiveB MyB
,就可以根据bshape
和bdistribute
定义的bdistribute
和gdistributeDefault
来定义1
。
答案 0 :(得分:2)
一个折衷方案是删除第一个默认定义:在用户手动实现bshape
时,要求添加一行以获取{{1}的另一个“默认”实现并不过分}。
bdistribute
所以实例看起来像这样:
class FunctorB b => DistributiveB b where
bdistribute :: Distributive f => f (b g) -> b (Compose f g)
default bdistribute :: CanDeriveDistributiveB b f g => ...
bdistribute = ...
bshape :: b ((->) (b Identity))
bshape = ...
-- Default implementation of bdistribute with an explicitly defined bshape
bdistributeDefault :: DistributiveB b => f (b g) -> b (Compose f g)
bdistributeDefault x = bmap (\f -> Compose $ fmap f . bsequence' <$> x) bshape