Yes, they perform the same, but only by accident. In ghci:
> :i .
(.) :: (b -> c) -> (a -> b) -> (a -> c) -- Defined in ‘GHC.Base’
infixr 9 .
Since it is infixr
, foo . foo . foo
parses as foo . (foo . foo)
, and so we can shortcut writing foo . foo . foo . ...
a billion times with foldr
. So:
> let foo :: a -> b -> c; foo = undefined
> foldr (.) id (replicate 1000000000 foo) ()
*** Exception: Prelude.undefined
CallStack (from HasCallStack):
error, called at libraries/base/GHC/Err.hs:79:14 in base:GHC.Err
undefined, called at <interactive>:1:5 in interactive:Ghci1
It returns almost immediately. On the other hand, the following two hang for a while:
> foldl (.) id (replicate 1000000000 foo) ()
> foldr (flip (.)) id (replicate 1000000000 foo) ()
However, I must stress again that this is a coincidence of GHC's implementation, not a guarantee made by the semantics of the language. It so happens that GHC's implementation of imprecise exceptions quickly notices that this will be an error (and throw's the left-most foo
's error) in the case of foldr (.)
, but doesn't notice as quickly for foldl (.)
. And of course in the case where foo
is not just an error, but has to do some actual computation, that computation will need to be performed as many times as it appears in the string of compositions -- GHC is pretty amazing, but not magical.