你失去的最大的东西是多态递归。考虑 Okasaki 的可连接列表:
data Cat q a = Empty | Cat a (q (Cat q a))
我们可以写
instance Foldable q => Foldable (Cat q) where
foldMap _ Empty = mempty
foldMap f (Cat a q) = f a <> foldMap (foldMap f) q
但是如果我们尝试使用 just MonoFoldable
,我们就会陷入困境。q
, ,上的必要实例约束forall x . (MonoFoldable (q x), Element (q x) ~ x)
不能以任何通常的方式表达。可能可以解决这个Data.Constraint.Forall
问题,但它变得非常难看。
一个较小的问题是代码可能会获得更复杂的类型签名。例如,
osum :: (MonoFoldable c, Num (Element c)) => c -> Element c
让我觉得不如
sum :: (Foldable f, Num n) => f n -> n
修复很简单:将定义更改MonoFoldable
为
class (a ~ Element c) => MonoFoldable' a c where ...
这会给你
osum' :: (MonoFoldable' n c, Num n) => c -> n
或者,完全报废Element
并使用
class MonoFoldable'' a c | c -> a
这给出了类似的简化签名。
不幸的是,Michael Snoyman 在这一点上不同意我的观点。我可能会编写自己的包装程序包来公开我喜欢的 API。
更新:现在我们有了QuantifiedConstraints
语言扩展,实际上可以Foldable
用MonoFoldable
!