理解`foldM`

Kev*_*ith 7 haskell

我正在关注foldM以获得如何使用它的直觉.

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

在这个简单的例子中,我简单地回来了[Just 100].但是,如果我想使用该b怎么办?

ghci> foldM (\a _ -> return a) (Just 100) [1,2,3] :: [Maybe Int]
[Just 100]
Run Code Online (Sandbox Code Playgroud)

我很困惑如何使用b内部(a -> b -> m a).

请帮助我获得这个功能的直觉以及如何使用b.

Dan*_*ner 12

这是一个愚蠢的例子.假设我们想要对列表求和,并确保部分总和从未超过(例如)10; 从而:

> let ensure p x = x <$ guard (p x)
> foldM (\a b -> ensure (<10) (a+b)) 0 [1,2,3] :: Maybe Integer
Just 6
> foldM (\a b -> ensure (<10) (a+b)) 0 [5,5,5,-10] :: Maybe Integer
Nothing
Run Code Online (Sandbox Code Playgroud)


Bak*_*riu 5

我相信你有问题,foldl而不是foldM.foldM基本上只是一个非常小的变化foldl.

所以考虑:

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

"发生"的是: - 如果xs == []那么x返回.- 否则f称为:f x (xs !! 0)获取结果值y :: a.然后f被称为:f y (xs !! 1),获得z.然后我们去f z (xs !! 2)

正如您所看到的,每次调用f都会将当前结果传递到该点,并将输入中的下一个元素传递给列表中的下一个元素.因此,只要您想将列表缩减为单个值并且您想要执行的计算是"顺序",即从第一个元素计算值,然后从此值计算值,并使用以下元素计算新值,从这个和第二个元素你计算一个新的等.

例如:

f ys x = map (+x) ys ++ [x]
foldl f [] [1,2,3]
Run Code Online (Sandbox Code Playgroud)

生产:

[6, 5, 3]
Run Code Online (Sandbox Code Playgroud)

因为:

  • f [] 1 = [1]
  • f [1] 2 = [1+2, 2] = [3, 2]
  • f [3, 2] 3 = [3+3, 2+3, 3] = [6, 5, 3]

为了更好地了解foldlfoldr工作,请参阅:

现在,foldMfoldl现在的f :: a -> b -> a类型相同f :: a -> b -> m a.这意味着将当前结果与下一个元素组合在一起的函数是monadic动作,即它可以产生效果.

例如,考虑:

f ys x = do
    let a = map (+x) ys ++ [x]
    print a
    return a

foldM f [] [1,2,3]
Run Code Online (Sandbox Code Playgroud)

会发生什么是文字:

[1]
[3,2]
[6,5,3]
Run Code Online (Sandbox Code Playgroud)

得到打印,值[6, 5, 3]是monadic动作的返回值.