考虑以下自由幺半群的类型类。
class FreeMonoid f where
inj :: a -> f a
univ :: Monoid m => (a -> m) -> f a -> m
inj
向自由幺半群注入(inject)一个值,univ
是自由幺半群的普遍性质。
此类的实例应满足以下定律。
- 身份:
univ f . inj = f
- 空空:
univ f mempty = mempty
- 免费追加:
univ f (m <> n) = univ f m <> univ f n
请注意,如果 f
是 FreeMonoid
的实例然后(f a)
必须是 Monoid
的实例.否则,后两条定律没有意义。那么,我该如何指定这个约束呢?这是我尝试过的。
class Monoid (f a) => FreeMonoid f where
inj :: a -> f a
univ :: Monoid m => (a -> m) -> f a -> m
没有这个约束,使用这个类就不方便了。例如,考虑以下函数。
mapFreeMonoid :: (FreeMonoid f, Monoid (f b)) => (a -> b) -> f a -> f b
mapFreeMonoid f = univ (inj . f)
自 f
是 FreeMonoid
的实例, 我们不必指定 Monoid (f b)
约束。理想情况下,我们应该能够如下定义上述函数。
mapFreeMonoid :: FreeMonoid f => (a -> b) -> f a -> f b
mapFreeMonoid f = univ (inj . f)
最佳答案
您可以尝试使用 QuantifiedConstraints
扩展进行试验。
class (forall a. Monoid (f a)) => FreeMonoid f where
...
然后您的代码可以在没有额外约束的情况下进行编译。
mapFreeMonoid :: FreeMonoid f => (a -> b) -> f a -> f b
mapFreeMonoid f = univ (inj . f)
关于haskell - 如何为自由幺半群定义父类(super class)约束?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74928908/