我有数据类型:
data Stuff s = Stuff { name :: s, idx :: Int }
并希望通过以下实现将其变为幺半群:
tmappend :: Stuff s -> Stuff t -> Stuff (s,t)
tmappend s1 s2 = Stuff (name s1, name s2) (idx s1 + idx s2)
tzero :: Stuff ()
tzero = Stuff () 0
请注意,可以通过mconcat
获得任意嵌套的元组。
但是tmappend目前正在违反mappend
的类型签名。这实际上是一个幺半群吗?可以将它制作成具有更好类型表示的那个。
答案 0 :(得分:16)
这被称为松散的monoidal仿函数。我强烈建议您阅读this paper,其中显示了Applicatives是一种松散的monoid类型,您可以将您的类型重新表述为Applicative
并获得等效的界面:
instance Applicative Stuff where
pure a = Stuff a 0
(Stuff f m) <*> (Stuff x n) = Stuff (f x) (m + n)
tmappend :: (Applicative f) => f a -> f b -> f (a, b)
tmappend fa fb = (,) <$> fa <*> fb
tzero :: (Applicative f) => f ()
tzero = pure ()
请注意,tmappend
和tzero
适用于所有Applicative
,而不只是Stuff
。我链接的论文更详细地讨论了这个习语。