Haskell是否有foldlM'函数?

9
如何严格地对单子进行折叠?Data.Foldable中有严格的foldl'和单子的foldlM,但没有严格的foldlM'?这种严格性是否由单子本身定义?如果是这样,那么如何确定它是什么?
想象一下,我必须确定一个巨大的环元素列表的乘积是否为零,但我的环不是整环,即它包含零除数。在这种情况下,我应该尾递归地将我的乘法***折叠到列表中,但在乘积变为零时立即返回False,而不是等待完整的乘积。
safelist :: [p] -> Bool
safelist [] = True
safelist (x:xs) = snd $ foldl' f (x,True) xs
   where  f (u,b) v = (w, b && w /= Zero)  where  w = u *** v

也许我能使用 Maybe 函子的 foldlM 来简化这段代码,但是这样做似乎缺少必要的严格性。

1个回答

11

没有这样的标准函数,但很容易定义:

foldM' :: (Monad m) => (a -> b -> m a) -> a -> [b] -> m a
foldM' _ z [] = return z
foldM' f z (x:xs) = do
  z' <- f z x
  z' `seq` foldM' f z' xs

这只是标准的foldM,但其中有与foldl'相同的seq(相对于foldl)。它可能没有定义在任何标准库中,因为它不太可能非常有用:对于大多数单子,(>>=)是“严格”的,意味着你需要使用左折叠而不会溢出栈;只有在您过多储存返回值本身的过多值时才有用,但foldM的一个有用的应用将对来自上一个步骤的值执行一些单子计算,这使得这种情况不太可能发生。

我认为您的代码已经足够简单了;我怀疑foldM'是否会使它更加优雅。


啊,我想如果单子里有严格标志的话,它可能会使事情变得严格,但否则不会。而且没有标准的单子这样做。谢谢! - Jeff Burdges
3
@JeffBurdges - 这里是一个关于单子>>=在严格与懒惰方面的即兴观察:https://dev59.com/7msy5IYBdhLWcg3w4x_c#8250334 - Dan Burton
实际上,如果您的 (>>=) 太慵懒,foldM' 也不会有所帮助,因为强制执行由惰性 State monad 返回的值并不一定会强制执行状态。 - ehird

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接