foldM:
foldM :: Monad m => (a -> b -> m a) -> a -> [b] -> m a
我试图创建一个foldM的示例,该示例只是将列表[1,2,3]的每个元素附加到其自身。

基于我对foldM的初步(错误)理解,我期望[[1], [2], [3]]作为以下内容的输出:

ghci> let f = (\xs x -> [x] : [xs])

但是我错了:
ghci> foldM f [] [1,2,3]
[[3],[2],[3],[1],[3],[2],[3],[]]

请说明此示例中发生的情况。

最佳答案

阅读文档并在GHCi中对foldM进行了一些调整之后,我想我可以解释您的示例中发生的情况。让我们重新检查foldM的类型签名:

foldM :: Monad m => (a -> b -> m a) -> a -> [b] -> m a

根据这种类型签名,我们可以得出结论foldM接受一个函数(a -> b -> m a)并将其应用于列表的每个元素([b])。第二个参数是在“首次调用”中传递给函数的初始值。后续调用使用应用该函数的结果值(从m a中“提取”的一个)。

因此,当您执行以下操作时:
ghci> let f = (\xs x -> [x] : [xs])
ghci> foldM f [] [1,2,3]
[[3],[2],[3],[1],[3],[2],[3],[]]

它等效于:
ghci> ([] `f` 1) >>= (`f` 2) >>= (`f` 3)
ghci> [[3],[2],[3],[1],[3],[2],[3],[]]

如果将上面的代码分成以下子表达式,我们可以更清楚地了解发生了什么:
ghci> ([] `f` 1)
ghci> [[1],[]]
ghci> ([] `f` 1) >>= (`f` 2)
ghci> [[2],[1],[2],[]]
...

函数f以一个列表和一个值作为参数,创建一个单例列表(将值放入其自己的列表中)并将其添加到列表中。最初,当我们有一个空列表时,结果很明显:[[1],[]](这是类型签名中的"m a")。现在,正如我之前所说,要再次调用f,有必要从该结果中获取新的"a"值。这次,我们调用f传递提取的值和提供的列表中的下一个值(即2中的[1,2,3])。问题是,考虑到我们的"m a"[[1],[]],我们应该将哪个列表作为f的第一个参数传递:[1][]?答案取决于列表的>>=运算符的行为,可以将其视为非确定性计算,该运算将给定函数应用于给定列表中的每个元素并组合结果。对于示例中的此特定步骤,将针对两个不同的第一个参数ff [1] 2两次调用f [] 2

我试图根据作者给出的示例来回答这个问题,但是在这种特殊情况下用来说明foldM行为的monadic链可以用来推断任何Monad。

关于haskell - 简单的 `foldM`示例,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/25517414/

10-09 17:09