1

我正在尝试实现一个通常将列表的第一个元素放入 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]

有任何想法吗?

4

2 回答 2

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没有关联。

于 2017-02-02T15:11:51.100 回答
1

一般来说,你不能这样做,因为函数不知道Foo调用函数时会使用哪个实例,这意味着它没有决定返回return s或的依据return (s:sx)

在这种特殊情况下,当is时有一种解决方法(请参阅@marc 的答案)。FooMonadPlus

于 2017-02-02T14:41:37.213 回答