在Haskell中列出monad的实例 - 为什么在bind-operation中使用concat?

Lyn*_*dra 2 monads haskell function list

我在这里找到了一些问题:重新定义monad list实例.我现在正试着把头包裹在monad周围.但是我需要一些帮助,我不会将列表的实例定义作为monad.

这是我给monad的列表实例的定义:

    instance Monad [] where
    xs >>= f = concat $ map f xs
    return x = [x]
    fail _ = []
Run Code Online (Sandbox Code Playgroud)

我不明白,为什么我需要在bind-function中使用concat.这是我的定义(>>=):

    (>>=) :: Monad m => m a -> (a -> m b) -> m b
Run Code Online (Sandbox Code Playgroud)

所以我有一些monadic值m a和一个函数,取一个值a并产生一个m b作为参数给出的monadic值.我' a从'进入' m a函数(a -> m b),因此得到一个monadic值m b.用我自己的话说:bind-operator (>>=)允许链接monadic函数(返回monadic值),其中早期函数的输出值是下一个函数的输入.对?

回到列表实例.在每个值上map f xs使用该函数.结果如此.这就是我想要的全部与否?我该怎么用?定义如下:fxsmap (*2) [1,2,3][2,4,6]concatconcat

    concat :: [[a]] -> [a]
Run Code Online (Sandbox Code Playgroud)

为什么我在(>>=)-function中获得列表列表?是因为list是monad而且我从该列表中获取每个值以将其提供给f并且map只获得单例输入?但是,如何迭代整个列表呢?"挑选每个价值"在哪里发生?如果map将整个列表xs作为输入(这就是我理解它的原因)为什么我应该得到一个列表列表?

chi*_*chi 7

如果

x :: [a]
f :: a -> [b]
Run Code Online (Sandbox Code Playgroud)

然后

map f :: [a] -> [[b]]
map f x :: [[b]]
Run Code Online (Sandbox Code Playgroud)

所以,我们需要将后者扁平化[b].这是通过concat.

注意如何f生成列表,因此map将其列入列表列表.这是至关重要的:如果f没有生成列表但是f :: a->b我们不需要concat- 我们甚至不需要monad,因为提供的仿函数fmap=map :: (a->b) -> [a] -> [b]就足够了.

monad相对于functor的额外好处主要在于让fmonadic类型产生一个值.