Hi Olaf -
I'd be interested whether there is a way to check which of my lists in the source code the compiler managed to "deforest" away. Which intermediate files should I look at? What are the tools to inspect?
Good question, and I don't know an easy answer. The general advice is running ghc with "-ddump-simpl" but I find it quite challenging to scan the output. Here is a simple case where it works: $ cat Fuse.hs main = print $ sum $ map (^2) [1 .. 1000 :: Int] $ ghc -fforce-recomp -ddump-simpl -O0 Fuse.hs no optimisation - shows that "main" calls "map" etc. $ ghc -fforce-recomp -ddump-simpl -O2 Fuse.hs fusion works - nice non-allocating inner loop (lists gone, and Int replaced by Int#) Rec { -- RHS size: {terms: 18, types: 3, coercions: 0} Main.$wgo [InlPrag=[0], Occ=LoopBreaker] :: GHC.Prim.Int# -> GHC.Prim.Int# -> GHC.Prim.Int# [GblId, Arity=2, Caf=NoCafRefs, Str=DmdType <S,1*U><S,U>] Main.$wgo = \ (w_s5kV :: GHC.Prim.Int#) (ww_s5kZ :: GHC.Prim.Int#) -> case w_s5kV of wild_Xn { __DEFAULT -> Main.$wgo (GHC.Prim.+# wild_Xn 1#) (GHC.Prim.+# ww_s5kZ (GHC.Prim.*# wild_Xn wild_Xn)); 1000# -> GHC.Prim.+# ww_s5kZ 1000000# } end Rec } but the challenge is to find the path from "main" to that, wading through several other functions that may or may not be related. I can imagine a source annotation like "in the code compiled from this function f, that constructor C should never be called" but this is certainly not easy. Do we really mean "never", or do we mean "only a bounded number of times" (that is, not in the inner loop). Perhaps there is no code for f itself, because it gets inlined. But yes, *some* automated analysis (and human-readable print-out) of the code after simplification would be nice. This could be done as a compiler plug-in? https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/extending_gh... - J.