Fold/build fails to fire when using applicative operators
See also
This program does not compile optimally:
import Data.Foldable
foo :: Int -> IO ()
foo x = print x
{-# OPAQUE foo #-}
main = for_ (liftA2 (,) [0 .. 10] [0 .. 10]) (\(x,y) -> foo (x + y))
I expected all the lists to fuse away, but looking at the core shows that some lists remain:
Rec {
go3_a2fy
= \ x_a2fz ->
: (I# x_a2fz)
(case x_a2fz of wild_X1E {
__DEFAULT -> go3_a2fy (+# wild_X1E 1#);
10# -> []
})
end Rec }
ys_a1yw = go3_a2fy 0#
Rec {
$wgo3_s2gs
= \ x_s2gk eta_s2gl ->
join {
exit_X2 eta_X1
= case x_s2gk of wild_X1E {
__DEFAULT -> $wgo3_s2gs (+# wild_X1E 1#) eta_X1;
10# -> eta_X1
} } in
joinrec {
go1_s2fO ds_a2fI eta_X1
= case ds_a2fI of {
[] -> jump exit_X2 eta_X1;
: y_a2fL ys_a2fM ->
case ((foo (case y_a2fL of { I# y_a2g9 -> I# (+# x_s2gk y_a2g9) }))
`cast` <Co:2> :: ...)
eta_X1
of
{ (# ipv_a1ha, ipv1_a1hb #) ->
jump go1_s2fO ys_a2fM ipv_a1ha
}
}; } in
jump go1_s2fO ys_a1yw eta_s2gl
end Rec }
main_s2gb
= \ eta_s2gl ->
case $wgo3_s2gs 0# eta_s2gl of ww_s2go { __DEFAULT ->
(# ww_s2go, () #)
}
It seems that ys_a1yw
is floated out too soon, which separates the foldr
from the build
and prevents fusion. After the first simplifier pass, the core looks like this:
ys_a1yw
= build (\ @b_a1yK c_a1yL n_a1yM -> eftIntFB c_a1yL n_a1yM 0# 10#)
main
= eftIntFB
(\ ds_a1yA ds1_a1yB ->
foldr
((\ ds2_a1yC ds3_a1yD s_a1h8 ->
case ((foo ($fNumInt_$c+ ds_a1yA ds2_a1yC)) `cast` <Co:2> :: ...)
s_a1h8
of
{ (# ipv_a1ha, ipv1_a1hb #) ->
(ds3_a1yD `cast` <Co:2> :: ...) ipv_a1ha
})
`cast` <Co:10> :: ...)
ds1_a1yB
ys_a1yw)
((\ s_a1yg -> (# s_a1yg, () #)) `cast` <Co:3> :: ...)
0#
10#
The fusion does happen if I replace liftA2
by its definition:
main = for_ [(,) x y | x <- [0 .. 10], y <- [0 .. 10]] (\(x,y) -> foo (x + y))
Environment
- GHC version used: 9.6.4 and 9.8.2