haskell - 具有默认值的相互递归定义的类型类方法
问题描述
我想定义一个具有两种方法的类型类,其中实现任何一种方法就足够了(但如果需要,您可以独立实现这两种方法)。Eq
这种情况与, wherex == 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
,我可以这样做: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
解决方案
一个折衷方案是放弃第一个默认定义:当用户手动实现bshape
时,要求添加一行以从中获取另一个“默认”实现并不过分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
所以实例看起来像这样:
-- Generic default
instance DistributiveB MyB
-- Manual bshape
instance DistributiveB MyB where
distribute = distributeDefault -- one extra line of boilerplate
bshape = ... -- custom definition
-- Manual distribute
instance DistributiveB MyB where
distribute = ...
-- bshape has a default implementation
推荐阅读
- python - Plotly 多行数据框
- asp.net-mvc-4 - 带有引导程序的 ASP.net 导航栏
- javascript - 事件发生后 localStorage 未重置为零
- python - 使用相同 Span 标签的表中的 Beautifulsoup 文本
- php - 使用 PHP 从 SQL Server 获取数组?
- python - 使用字典理解后更新字典值
- javascript - 仅从 foreach 循环接收最后一个 onclick 事件
- php - 无法在 React 中从我的 API 服务器获取数据
- matlab - 矩阵周期边界条件 Matlab
- python - 组合由循环产生的多个列表