content: module Main where
  
  -- This test works efficiently because the full laziness
  -- pass now floats out applications
  --      \x -> f y (x+1)
  -- It'll float out the (f y) if that's a redex
  
  loop :: Double -> [Int] -> Double
  {-# NOINLINE loop #-}
  loop x [] = x
  loop x (n:ns) = x `seq` loop (x ^ n) ns
  
  main = print $ loop 1 (replicate 10000000 5)
  
  ----------------------------------------------------
  {-  Roman's message of May 2010
  
  I tried running nofib with -fno-method-sharing (we discussed this at some point). These are the results:
  
  --------------------------------------------------------------------------------
          Program           Size    Allocs   Runtime   Elapsed
  --------------------------------------------------------------------------------
  
              Min          -0.3%    -25.0%    -12.5%     -9.9%
              Max          +0.2%   +159.1%    +90.0%    +84.7%
   Geometric Mean          -0.0%     +2.2%     +6.8%     +5.1%
  
  This is the worst program:
  
           simple          +0.2%   +159.1%    +65.3%    +63.9%
  
  I looked at it a bit and came up with this small example:
  
  ----
  loop :: Double -> [Int] -> Double
  {-# NOINLINE loop #-}
  loop x [] = x
  loop x (n:ns) = x `seq` loop (x ^ n) ns
  
  main = print $ loop 1 (replicate 10000000 5)
  ----
  
  This is over 2x slower with -fno-method-sharing. The culprit is, of
  course, (^). Here is the difference:
  
  Without -fno-method-sharing:
  
  ----
  ^_rVB :: GHC.Types.Double -> GHC.Types.Int -> GHC.Types.Double ^_rVB =
    GHC.Real.^
      @ GHC.Types.Double
      @ GHC.Types.Int
      GHC.Float.$fNumDouble
      GHC.Real.$fIntegralInt
  
  Main.loop [InlPrag=NOINLINE (sat-args=2), Occ=LoopBreaker]
    :: GHC.Types.Double -> [GHC.Types.Int] -> GHC.Types.Double Main.loop =
    \ (x1_aat :: GHC.Types.Double) (ds_drG :: [GHC.Types.Int]) ->
      case ds_drG of _ {
        [] -> x1_aat;
        : n_aav ns_aaw ->
          case x1_aat of x2_aau { GHC.Types.D# ipv_srQ ->
          Main.loop (^_rVB x2_aau n_aav) ns_aaw
          }
      }
  ----
  
  With:
  
  ----
  Main.loop [InlPrag=NOINLINE (sat-args=2), Occ=LoopBreaker]
    :: GHC.Types.Double -> [GHC.Types.Int] -> GHC.Types.Double Main.loop =
    \ (x1_aat :: GHC.Types.Double) (ds_drD :: [GHC.Types.Int]) ->
      case ds_drD of _ {
        [] -> x1_aat;
        : n_aav ns_aaw ->
          case x1_aat of x2_aau { GHC.Types.D# ipv_srN ->
          Main.loop
            (GHC.Real.^
               @ GHC.Types.Double
               @ GHC.Types.Int
               GHC.Float.$fNumDouble
               GHC.Real.$fIntegralInt
               x2_aau
               n_aav)
            ns_aaw
          }
      }
  ----
  
  This is a bit disappointing. I would have expected GHC to float out
  the application of (^) to the two dictionaries during full laziness
  (note that (^) has arity 2 so the application is oversaturated). Why
  doesn't that happen? SetLevels (if this is the right place to look)
  has this:
  
  -}
  