我正在尝试实现一个通常将列表的第一个元素放在monad中的函数,但如果monad是一个列表,则返回整个列表:
putInMonad :: MonadPlus m => [a] -> m a
putInMonad (s:sx) = return s
putInMonad _ = mzero
putInMonad [1,2,3] :: Maybe Int
应该返回Just 1
和
putInMonad [1,2,3] :: [] Int
应该返回[1,2,3]
。
有什么想法吗?
答案 0 :(得分:5)
在您的特定用例中,您可以利用msum
:
putInMonad :: MonadPlus m => [a] -> m a
putInMonad x = msum $ map return x
然后两个例子都有效:
% putInMonad [1,2,3,4] :: Maybe Int
Just 1
% putInMonad [1,2,3,4] :: [Int]
[1,2,3,4]
但请注意Maybe
并非MonadPlus
,因为mplus
没有关联。
答案 1 :(得分:1)
通常,您不能这样做,因为函数在调用函数时无法知道将使用哪个Foo
实例,这意味着它没有决定返回return s
或{的依据。 {1}}。
在这种特殊情况下,return (s:sx)
为Foo
时有一种解决方法(请参阅@marc's answer)。