{- - A rather contrived example demonstrating the virtues of not floating join - points outward. -} module Main (main) where -- Calculate n `div` d `div` d by looping. {-# NOINLINE slowDivDiv #-} slowDivDiv :: Int -> Int -> Int slowDivDiv n d = let {-# NOINLINE divPos #-} divPos :: Int -> Int divPos n0 = -- This function is a join point (all calls are tail calls), so it -- never causes a closure allocation, so it doesn't help to float it -- out. Thus -fno-join-points causes a ~25% jump in allocations. let go n' i = case n' >= d of True -> go (n' - d) (i + 1) False -> i in go n0 0 in case n >= 0 of True -> divPos (divPos n) False -> divPos (-(divPos (-n))) -- It's important that divPos be called twice -- because otherwise it'd be a one-shot lambda -- and so the join point would be floated -- back in again. main = print $ sum [slowDivDiv n d | n <- [1..1000], d <- [1..1000]]