我之前定义了一个函数,它接受一个列表 Maybe
s 并将其变成 Maybe
一个列表,像这样:
floop :: [Maybe a] -> Maybe [a]
floop [] = Just []
floop (Nothing:_) = Nothing
floop (Just x:xs) = fmap (x:) $ floop xs
现在我想重新定义它以兼容更大类的容器,而不仅仅是列表,我发现它需要实现功能
foldr
, mappend
, mempty
, fmap
, 和 pure
;所以我认为以下类型行是合适的:floop :: (Foldable t, Functor t, Monoid t) => t (Maybe a) -> Maybe (t a)
因为(我认为)它确保为给定的容器实现了这些功能,但是它会导致以下错误:
Expecting one more argument to ‘t’
The first argument of ‘Monoid’ should have kind ‘*’,
but ‘t’ has kind ‘* -> *’
In the type signature for ‘floop'’:
floop' :: (Foldable t, Functor t, Monoid t) =>
t (Maybe a) -> Maybe (t a)
查了一下,发现
Monoid
的种类与Functor
的种类不同和 Foldable
,但我不明白为什么会这样,也不明白如何纠正错误。对于那些感兴趣的人,这是当前的实现:
floop :: (Foldable t, Functor t, Monoid t) => t (Maybe a) -> Maybe (t a)
floop xs = let
f :: (Foldable t, Functor t, Monoid t) => Maybe a -> Maybe (t a) -> Maybe (t a)
f Nothing _ = Nothing
f (Just x) ys = fmap (mappend $ pure x) ys
in
foldr f (Just mempty) xs
注意:我已经知道这已经作为一个内置函数存在 (
sequence
),但我打算将它作为一个学习练习来实现。
最佳答案
幺半群应用由 Alternative
描述类,使用 (<|>)
和 empty
而不是 mappend
和 mempty
:
floop :: (Foldable t, Alternative t) => t (Maybe a) -> Maybe (t a)
floop xs = let
f :: (Foldable t, Alternative t) => Maybe a -> Maybe (t a) -> Maybe (t a)
f Nothing _ = Nothing
f (Just x) ys = fmap ((<|>) $ pure x) ys
in
foldr f (Just empty) xs
关于haskell - 将类型参数限制为 Monoid,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41981432/