Skip to content

foldl' semantics changed from 4.7 to 4.8

foldl' is now defined as

foldl'           :: forall a b . (b -> a -> b) -> b -> [a] -> b
{-# INLINE foldl' #-}
foldl' k z0 xs =
  foldr (\(v::a) (fn::b->b) -> oneShot (\(z::b) -> z `seq` fn (k z v))) (id :: b -> b) xs z0

As far as I can tell, the Haskell 2010 report does not specify anything about the behavior of foldl'. In base 4.7, it was defined

foldl'           :: (b -> a -> b) -> b -> [a] -> b
foldl' f z0 xs0 = lgo z0 xs0
    where lgo z []     = z
          lgo z (x:xs) = let z' = f z x in z' `seq` lgo z' xs

These are not equivalent. In particular, with the old foldl',

foldl' (\_ _ -> 3) undefined "hello"

evaluates to 3, but with the new one, it throws an exception. If the old semantics are preferred, we can get them with

foldl'           :: forall a b . (b -> a -> b) -> b -> [a] -> b
{-# INLINE foldl' #-}
foldl' k z0 xs =
  foldr (\(v::a) (fn::b->b) -> oneShot (\(z::b) -> fn $! k z v)) (id :: b -> b) xs z0

The old semantics match the default Foldable instance. The advantage of the new semantics is that they're more consistent about strictness (unconditionally strict in the accumulator), but that blocks out idioms like

foldl' f (error "Empty list") ...

I don't remember this being discussed.

Trac metadata
Trac field Value
Version 7.10.2
Type Bug
TypeOfFailure OtherFailure
Priority normal
Resolution Unresolved
Component Core Libraries
Test case
Differential revisions
BlockedBy
Related
Blocking
CC ekmett, nomeata
Operating system
Architecture
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information