因此,了解它的最好方法就是这样做。下面有一个foldlMusing foldl代替的实现foldr。这是一个很好的练习,请尝试一下,然后再提出我建议的解决方案。该示例说明了我为实现此目标所做的所有推理,这可能与您的不同,并且可能有偏见,因为我已经知道使用函数累加器。
第1步:让我们试着写foldlM在条款foldl
-- this doesn't compile because f returning type is (m b) and not just (b) 
foldlM :: (Foldable t, Monad m) => (b -> a -> m b) -> b -> t a -> m b
foldlM f z0 xs = foldl f z0 xs 
-- So let substitute f by some undefined f'
foldlM :: (Foldable t, Monad m) => (b -> a -> m b) -> b -> t a -> m b
foldlM f z0 xs = foldl f' z0 xs
  where f' = undefined
-- cool, but f' should use f somehow in order to get the monadic behaviour
foldlM :: (Foldable t, Monad m) => (b -> a -> m b) -> b -> t a -> m b
foldlM f z0 xs = foldl f' z0 xs
  where f' b a = f somethingIDontkNow 
在这里,您意识到这f'是纯粹的,您需要提取结果以f进行类型匹配。唯一提取单调值的方法是使用>>=运算符,但是使用此类运算符后必须立即对其进行换行。
因此得出一个结论:每次结束时,我都想完全拆开此monad,请放弃。不是正确的方法
第2步:让我们尝试使用foldlM,foldl但首先使用[]可折叠,因为它很容易进行模式匹配(即,我们实际上不需要使用fold)
-- This is not very hard. It is pretty standard recursion schema. :)
foldlM' :: (Monad m) => (b -> a -> m b) -> b -> [a] -> m b
foldlM' f z0 []     = return z0
foldlM' f z0 (x:xs) = f z0 x >>= \c -> foldlM' f c xs
好的,那很容易。让我们将定义与foldl列表的常规定义进行比较
foldlM' :: (Monad m) => (b -> a -> m b) -> b -> [a] -> m b
foldlM' f z0 []     = return z0
foldlM' f z0 (x:xs) = f z0 x >>= \c -> foldlM' f c xs
myfoldl :: (b -> a -> b) -> b -> [a] -> b
myfoldl f z0 []     = z0
myfoldl f z0 (x:xs) = foldl f (f z0 x) xs
凉!!他们几乎一样。琐碎的事情是完全相同的事情。递归的情况有些不同,您想编写更多类似的内容:foldlM' f (f z0 x) xs。但是is不像第1步那样进行编译,因此您可能会认为还可以,我不想应用f,只是持有这样的计算并用进行组合>>=。我想写些更有 foldlM' f (f z0 x >>=) xs意义的东西 ...
步骤3意识到要累积的是函数组成而不是结果。(在这里,我可能已经对它有所了解,因为您已经发布了它)。
foldlM :: (Foldable t, Monad m) => (b -> a -> m b) -> b -> t a -> m b
foldlM f z0 xs = foldl f' initFunc xs
  where initFunc = undefined :: b -> m b
        f'       = undefined :: (b -> m b) -> a -> (b -> m b) -- This type signature can be deduce because f' should be applied to initFunc and a's from t a. 
通过initFunc第二步(递归定义)的知识和使用我们的知识,我们可以推论得出initFunc = return。f'知道f'应该使用f和可以完成的定义>>=。
foldlM :: (Foldable t, Monad m) => (b -> a -> m b) -> b -> t a -> m b
foldlM f z0 xs = foldl f' return xs z0
--                        ^^^^^^
--                        |- Initial value
  where f' b a = \bvalue -> b bvalue >>= \bresult -> f bresult a -- this is equivalent to (b >=> \result -> f result a) which captures the sequence behaviour of the implementation
--         ^      ^^^^^^                  ^^^^^^^
--         |      |                       |- This is the result of previous computation
--         |      |- f' should return a function b -> m b. Any time you have to return a function, start writing a lambda  
--         |- This b is the accumulated value and has type b -> m b
-- Following the types you can write this with enough practise
如您所见,做到这一点并不难。它需要实践,但是我不是专业的haskell开发人员,我自己可以做,这是一个实践问题