考慮以下自由幺半群的類型類。
class FreeMonoid f where
inj :: a -> f a
univ :: Monoid m => (a -> m) -> f a -> m
inj
將一個值注入到自由幺半群中,而univ
是自由幺半體的普遍性質。
此類的實例應滿足以下規則。
- Identity:
univ f . inj = f
- 空閑空:
univ f mempty = mempty
- 免費附加:
univ f (m <> n) = univ f m <> univ f n
注意,如果f
是FreeMonoid
的一個實例,那么(f a)
必須是univ f (m <> n) = univ f m <> univ f n
的實例。否則,最后兩條定律就沒有意義了。那么,如何指定此約束?這是我嘗試過的。
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
擴展名。然后在沒有附加約束的情況下編譯代碼。