9

一个人如何严格地折叠一个单子? Data.Foldable有严格foldl'的和一元的foldlM,但没有严格的foldlM'?单子本身是否以某种方式定义了严格性?如果是这样,如何确定它是什么?

想象一下,我必须确定大量环元素的乘积是否为零,但我的环不是整数域,即它包含零除数。在这种情况下,我应该递归地foldl将我的乘法***拖到列表上,但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

我也许可以使用Maybemonad稍微简化此代码,foldlM但这样做似乎缺乏所需的严格性。

4

1 回答 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,但与seq它的 ing相同foldl'(与 相比foldl)。它可能没有在任何标准中定义,因为它可能不是那么有用:对于大多数 monad,(>>=)在您需要使用左折叠而不溢出堆栈的意义上是“严格的”;这仅在返回值本身中有过多的 thunk 时才有用,但有用的应用程序foldM将使用最后一步的值执行一些单子计算,这不太可能。

我认为您的代码很简单;我怀疑foldM'会让它更优雅。

于 2012-01-18T23:32:33.690 回答