Skip to content

Instantly share code, notes, and snippets.

@monadplus
Created August 1, 2022 14:11
Show Gist options
  • Save monadplus/6c8f6e6fe729753c5897d5b24408fc81 to your computer and use it in GitHub Desktop.
Save monadplus/6c8f6e6fe729753c5897d5b24408fc81 to your computer and use it in GitHub Desktop.
Haskell: tail recursion affects performance?

ghc -O2 -ddump-simpl -ddump-to-file Main.hs:


==================== Tidy Core ====================
2022-08-01 14:09:19.73363688 UTC

Result size of Tidy Core
  = {terms: 178, types: 217, coercions: 9, joins: 0/0}

-- RHS size: {terms: 1, types: 0, coercions: 0, joins: 0/0}
lvl_r2eH :: GHC.Prim.Addr#
[GblId, Unf=OtherCon []]
lvl_r2eH = "Main.hs:(5,1)-(6,34)|function f"#

-- RHS size: {terms: 2, types: 2, coercions: 0, joins: 0/0}
lvl1_r2eI :: ()
[GblId, Str=b, Cpr=b]
lvl1_r2eI
  = Control.Exception.Base.patError @GHC.Types.LiftedRep @() lvl_r2eH

Rec {
-- RHS size: {terms: 19, types: 23, coercions: 0, joins: 0/0}
f [Occ=LoopBreaker] :: forall a. [a] -> [(a, a)]
[GblId, Arity=1, Str=<1L>, Unf=OtherCon []]
f = \ (@a_aVz) (ds_d19q :: [a_aVz]) ->
      case ds_d19q of {
        [] -> GHC.Types.[] @(a_aVz, a_aVz);
        : x1_av0 ds1_d19y ->
          case ds1_d19y of {
            [] -> case lvl1_r2eI of wild2_00 { };
            : x2_av1 xs_av2 ->
              GHC.Types.: @(a_aVz, a_aVz) (x1_av0, x2_av1) (f @a_aVz xs_av2)
          }
      }
end Rec }

-- RHS size: {terms: 1, types: 0, coercions: 0, joins: 0/0}
lvl2_r2eJ :: GHC.Prim.Addr#
[GblId, Unf=OtherCon []]
lvl2_r2eJ = "Main.hs:(10,3)-(11,48)|function g'"#

-- RHS size: {terms: 2, types: 2, coercions: 0, joins: 0/0}
lvl3_r2eK :: ()
[GblId, Str=b, Cpr=b]
lvl3_r2eK
  = Control.Exception.Base.patError
      @GHC.Types.LiftedRep @() lvl2_r2eJ

Rec {
-- RHS size: {terms: 22, types: 27, coercions: 0, joins: 0/0}
Main.g_g' [Occ=LoopBreaker]
  :: forall {a}. [(a, a)] -> [a] -> [(a, a)]
[GblId, Arity=2, Str=<L><1L>, Unf=OtherCon []]
Main.g_g'
  = \ (@a_aUX) (acc_av4 :: [(a_aUX, a_aUX)]) (ds_d197 :: [a_aUX]) ->
      case ds_d197 of {
        [] -> reverse @(a_aUX, a_aUX) acc_av4;
        : x1_awA ds1_d19n ->
          case ds1_d19n of {
            [] -> case lvl3_r2eK of wild2_00 { };
            : x2_awB xs_awC ->
              Main.g_g'
                @a_aUX
                (GHC.Types.: @(a_aUX, a_aUX) (x1_awA, x2_awB) acc_av4)
                xs_awC
          }
      }
end Rec }

-- RHS size: {terms: 3, types: 5, coercions: 0, joins: 0/0}
g :: forall a. [a] -> [(a, a)]
[GblId,
 Arity=1,
 Str=<1L>,
 Unf=Unf{Src=InlineStable, TopLvl=True, Value=True, ConLike=True,
         WorkFree=True, Expandable=True,
         Guidance=ALWAYS_IF(arity=0,unsat_ok=True,boring_ok=False)
         Tmpl= \ (@a_aUX) (eta_B0 [Occ=Once1] :: [a_aUX]) ->
                 Main.g_g' @a_aUX (GHC.Types.[] @(a_aUX, a_aUX)) eta_B0}]
g = \ (@a_aUX) -> Main.g_g' @a_aUX (GHC.Types.[] @(a_aUX, a_aUX))

-- RHS size: {terms: 1, types: 0, coercions: 0, joins: 0/0}
Main.$trModule4 :: GHC.Prim.Addr#
[GblId,
 Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True,
         WorkFree=True, Expandable=True, Guidance=IF_ARGS [] 20 0}]
Main.$trModule4 = "main"#

-- RHS size: {terms: 2, types: 0, coercions: 0, joins: 0/0}
Main.$trModule3 :: GHC.Types.TrName
[GblId,
 Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True,
         WorkFree=True, Expandable=True, Guidance=IF_ARGS [] 10 10}]
Main.$trModule3 = GHC.Types.TrNameS Main.$trModule4

-- RHS size: {terms: 1, types: 0, coercions: 0, joins: 0/0}
Main.$trModule2 :: GHC.Prim.Addr#
[GblId,
 Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True,
         WorkFree=True, Expandable=True, Guidance=IF_ARGS [] 20 0}]
Main.$trModule2 = "Main"#

-- RHS size: {terms: 2, types: 0, coercions: 0, joins: 0/0}
Main.$trModule1 :: GHC.Types.TrName
[GblId,
 Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True,
         WorkFree=True, Expandable=True, Guidance=IF_ARGS [] 10 10}]
Main.$trModule1 = GHC.Types.TrNameS Main.$trModule2

-- RHS size: {terms: 3, types: 0, coercions: 0, joins: 0/0}
Main.$trModule :: GHC.Types.Module
[GblId,
 Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True,
         WorkFree=True, Expandable=True, Guidance=IF_ARGS [] 10 10}]
Main.$trModule = GHC.Types.Module Main.$trModule3 Main.$trModule1

-- RHS size: {terms: 20, types: 15, coercions: 0, joins: 0/0}
z2_r2eL :: Int -> (Int, Int) -> Int
[GblId,
 Arity=2,
 Str=<1P(L)><1P(1P(L),1P(L))>,
 Cpr=1,
 Unf=OtherCon []]
z2_r2eL
  = \ (acc_aHv :: Int) (ds_d196 [OS=OneShot] :: (Int, Int)) ->
      case acc_aHv of { GHC.Types.I# ipv_s1m6 ->
      case ds_d196 of { (x1_aHw, x2_aHx) ->
      case x1_aHw of { GHC.Types.I# x_a1mb ->
      case x2_aHx of { GHC.Types.I# y_a1me ->
      GHC.Types.I# (GHC.Prim.+# (GHC.Prim.+# x_a1mb y_a1me) ipv_s1m6)
      }
      }
      }
      }

-- RHS size: {terms: 2, types: 0, coercions: 0, joins: 0/0}
Main.z1 :: Int
[GblId,
 Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True,
         WorkFree=True, Expandable=True, Guidance=IF_ARGS [] 10 10}]
Main.z1 = GHC.Types.I# 0#

-- RHS size: {terms: 3, types: 4, coercions: 0, joins: 0/0}
z :: [(Int, Int)] -> Int
[GblId,
 Arity=1,
 Str=<1L>,
 Unf=Unf{Src=InlineStable, TopLvl=True, Value=True, ConLike=True,
         WorkFree=True, Expandable=True,
         Guidance=ALWAYS_IF(arity=0,unsat_ok=True,boring_ok=False)
         Tmpl= \ (eta_B0 [Occ=Once1] :: [(Int, Int)]) ->
                 GHC.Base.foldr
                   @(Int, Int)
                   @(Int -> Int)
                   (\ (ds_a1m2 [Occ=Once1!] :: (Int, Int))
                      (ds1_a1m3 [Occ=Once1!, OS=OneShot] :: Int -> Int)
                      (v_a1m4 [Occ=Once1!, OS=OneShot] :: Int) ->
                      case v_a1m4 of { GHC.Types.I# ipv_s2dZ [Occ=Once1] ->
                      ds1_a1m3
                        (case ds_a1m2 of { (x1_aHw [Occ=Once1!], x2_aHx [Occ=Once1!]) ->
                         case x1_aHw of { GHC.Types.I# x_a1mb [Occ=Once1] ->
                         case x2_aHx of { GHC.Types.I# y_a1me [Occ=Once1] ->
                         GHC.Types.I# (GHC.Prim.+# (GHC.Prim.+# x_a1mb y_a1me) ipv_s2dZ)
                         }
                         }
                         })
                      })
                   (id @Int)
                   eta_B0
                   Main.z1}]
z = GHC.List.foldl' @(Int, Int) @Int z2_r2eL Main.z1

Rec {
-- RHS size: {terms: 13, types: 4, coercions: 0, joins: 0/0}
Main.main_go3 [Occ=LoopBreaker] :: GHC.Prim.Int# -> [Int]
[GblId, Arity=1, Str=<L>, Unf=OtherCon []]
Main.main_go3
  = \ (x_a2dv :: GHC.Prim.Int#) ->
      GHC.Types.:
        @Int
        (GHC.Types.I# x_a2dv)
        (case x_a2dv of wild_X1E {
           __DEFAULT -> Main.main_go3 (GHC.Prim.+# wild_X1E 1#);
           100000# -> GHC.Types.[] @Int
         })
end Rec }

Rec {
-- RHS size: {terms: 30, types: 36, coercions: 0, joins: 0/0}
Main.$wgo1 [InlPrag=[2], Occ=LoopBreaker]
  :: [(Int, Int)] -> GHC.Prim.Int# -> String
[GblId, Arity=2, Str=<1L><L>, Unf=OtherCon []]
Main.$wgo1
  = \ (w_s2dQ :: [(Int, Int)]) (ww_s2dU :: GHC.Prim.Int#) ->
      case w_s2dQ of {
        [] ->
          case GHC.Show.$witos ww_s2dU (GHC.Types.[] @Char) of
          { (# ww2_a1wX, ww3_a1wY #) ->
          GHC.Types.: @Char ww2_a1wX ww3_a1wY
          };
        : y_a1uq ys_a1ur ->
          case y_a1uq of { (x1_aHw, x2_aHx) ->
          case x1_aHw of { GHC.Types.I# x_a1mb ->
          case x2_aHx of { GHC.Types.I# y1_a1me ->
          Main.$wgo1
            ys_a1ur (GHC.Prim.+# (GHC.Prim.+# x_a1mb y1_a1me) ww_s2dU)
          }
          }
          }
      }
end Rec }

-- RHS size: {terms: 6, types: 4, coercions: 0, joins: 0/0}
Main.main2 :: String
[GblId,
 Unf=Unf{Src=<vanilla>, TopLvl=True, Value=False, ConLike=False,
         WorkFree=False, Expandable=False, Guidance=IF_ARGS [] 80 0}]
Main.main2
  = Main.$wgo1
      (Main.g_g' @Int (GHC.Types.[] @(Int, Int)) (Main.main_go3 1#)) 0#

-- RHS size: {terms: 5, types: 1, coercions: 0, joins: 0/0}
Main.main3 :: String
[GblId,
 Unf=Unf{Src=<vanilla>, TopLvl=True, Value=False, ConLike=False,
         WorkFree=False, Expandable=False, Guidance=IF_ARGS [] 70 0}]
Main.main3 = Main.$wgo1 (f @Int (Main.main_go3 1#)) 0#

-- RHS size: {terms: 13, types: 13, coercions: 0, joins: 0/0}
Main.main1
  :: GHC.Prim.State# GHC.Prim.RealWorld
     -> (# GHC.Prim.State# GHC.Prim.RealWorld, () #)
[GblId,
 Arity=1,
 Str=<L>,
 Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True,
         WorkFree=True, Expandable=True, Guidance=IF_ARGS [0] 90 0}]
Main.main1
  = \ (s_a1mw :: GHC.Prim.State# GHC.Prim.RealWorld) ->
      case GHC.IO.Handle.Text.hPutStr2
             GHC.IO.Handle.FD.stdout Main.main3 GHC.Types.True s_a1mw
      of
      { (# ipv_a1my, ipv1_a1mz #) ->
      GHC.IO.Handle.Text.hPutStr2
        GHC.IO.Handle.FD.stdout Main.main2 GHC.Types.True ipv_a1my
      }

-- RHS size: {terms: 1, types: 0, coercions: 3, joins: 0/0}
main :: IO ()
[GblId,
 Arity=1,
 Str=<L>,
 Unf=Unf{Src=InlineStable, TopLvl=True, Value=True, ConLike=True,
         WorkFree=True, Expandable=True,
         Guidance=ALWAYS_IF(arity=0,unsat_ok=True,boring_ok=True)
         Tmpl= Main.main1
               `cast` (Sym (GHC.Types.N:IO[0] <()>_R)
                       :: (GHC.Prim.State# GHC.Prim.RealWorld
                           -> (# GHC.Prim.State# GHC.Prim.RealWorld, () #))
                          ~R# IO ())}]
main
  = Main.main1
    `cast` (Sym (GHC.Types.N:IO[0] <()>_R)
            :: (GHC.Prim.State# GHC.Prim.RealWorld
                -> (# GHC.Prim.State# GHC.Prim.RealWorld, () #))
               ~R# IO ())

-- RHS size: {terms: 2, types: 1, coercions: 3, joins: 0/0}
Main.main4
  :: GHC.Prim.State# GHC.Prim.RealWorld
     -> (# GHC.Prim.State# GHC.Prim.RealWorld, () #)
[GblId,
 Arity=1,
 Str=<L>,
 Unf=Unf{Src=InlineStable, TopLvl=True, Value=True, ConLike=True,
         WorkFree=True, Expandable=True,
         Guidance=ALWAYS_IF(arity=0,unsat_ok=True,boring_ok=False)
         Tmpl= \ (eta_B0 [Occ=Once1, OS=OneShot]
                    :: GHC.Prim.State# GHC.Prim.RealWorld) ->
                 GHC.TopHandler.runMainIO1
                   @()
                   (Main.main1
                    `cast` (Sym (GHC.Types.N:IO[0] <()>_R)
                            :: (GHC.Prim.State# GHC.Prim.RealWorld
                                -> (# GHC.Prim.State# GHC.Prim.RealWorld, () #))
                               ~R# IO ()))
                   eta_B0}]
Main.main4
  = GHC.TopHandler.runMainIO1
      @()
      (Main.main1
       `cast` (Sym (GHC.Types.N:IO[0] <()>_R)
               :: (GHC.Prim.State# GHC.Prim.RealWorld
                   -> (# GHC.Prim.State# GHC.Prim.RealWorld, () #))
                  ~R# IO ()))

-- RHS size: {terms: 1, types: 0, coercions: 3, joins: 0/0}
:Main.main :: IO ()
[GblId,
 Arity=1,
 Str=<L>,
 Unf=Unf{Src=InlineStable, TopLvl=True, Value=True, ConLike=True,
         WorkFree=True, Expandable=True,
         Guidance=ALWAYS_IF(arity=0,unsat_ok=True,boring_ok=True)
         Tmpl= Main.main4
               `cast` (Sym (GHC.Types.N:IO[0] <()>_R)
                       :: (GHC.Prim.State# GHC.Prim.RealWorld
                           -> (# GHC.Prim.State# GHC.Prim.RealWorld, () #))
                          ~R# IO ())}]
:Main.main
  = Main.main4
    `cast` (Sym (GHC.Types.N:IO[0] <()>_R)
            :: (GHC.Prim.State# GHC.Prim.RealWorld
                -> (# GHC.Prim.State# GHC.Prim.RealWorld, () #))
               ~R# IO ())

module Main where
import Data.List (foldl')
f :: [a] -> [(a, a)]
f [] = []
f (x1 : x2 : xs) = (x1, x2) : f xs
g :: [a] -> [(a, a)]
g = g' [] where
g' acc [] = reverse acc
g' acc (x1 : x2 : xs) = g' ((x1, x2) : acc) xs
z :: [(Int, Int)] -> Int
z = foldl' (\ !acc (x1, x2) -> x1 + x2 + acc) 0
main = do
print $ z $ f [1..100000]
print $ z $ g [1..100000]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment