Haskell 简单的“foldM”示例

Haskell 简单的“foldM”示例,haskell,Haskell,查看foldM: foldM :: Monad m => (a -> b -> m a) -> a -> [b] -> m a foldM::Monad m=>(a->b->ma)->a->[b]->ma 我试图创建一个foldM的示例,它只是将列表的每个元素[1,2,3]附加到它自己 基于我对foldM的最初(错误)理解,我期望[[1]、[2]、[3]]作为以下内容的输出: ghci> let f = (\xs x -> [x] : [xs])

查看foldM:

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

我试图创建一个
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->ma)
,并将其应用于列表的每个元素(
[b]
)。第二个参数是在“第一次调用”中传递给函数的初始值。后续调用使用应用函数的结果值(从
ma
中“提取”的值)

因此,当您这样做时:

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],][]
(这是我们在类型签名中的
“ma”
)。现在,正如我前面所说,为了再次调用
f
,需要从该结果中获取新的
“a”
值。这一次,我们调用
f
传递提取的值和所提供列表中的下一个值(即
2
来自
[1,2,3]
)。问题是,考虑到我们的
“ma”
[[1],][]
,我们应该将哪个列表作为
f
的第一个参数传递:
[1]
[]
?答案取决于列表的
>=
操作符的行为,它可以被视为非确定性计算,将给定函数应用于给定列表中的每个元素并组合结果。对于示例中的此特定步骤,将为两个不同的第一个参数调用
f
f[1]2
f[]2


我试图根据作者给出的例子来回答这个问题,但在这种特殊情况下,用来明确
foldM
行为的一元链可以用来对任何一个单子进行推理。

你想要的只是一个规则的折叠。尝试使用
foldl
而不是
foldM
,然后尝试使用
f=(\xs x->return(x:xs))
foldM
。然后看看你能用
f
做些什么,看看它是如何与各种monad交互的。很好的解释-也许你应该添加到
foldM
的doc/source的链接。这很简单,因为要知道累加器是一个列表单子,以及它是如何绑定的。不久前,有一个关于
forM
应用函数生成list monad的问题。