1

To avoid CAF (resource sharing), I tried converting to function with dummy argument, but no success (noCafB). I've read How to make a CAF not a CAF in Haskell? so tried noCafC and noCafD. When compiled with -O0, then functions with dummy argument did evaluated every time. However, with -O2, it seems that GHC converts those functions to CAF. Is this intended behaviour (GHC's optimization)?

module Main where
import Debug.Trace

cafA :: [Integer]
cafA = trace "hi" (map (+1) $ [1..])
noCafB :: a -> [Integer]
noCafB _ = trace "hi" (map (+1) $ [1..])
noCafC :: a -> [Integer]
noCafC _ = trace "hi" (map (+1) $ [1..])
{-# NOINLINE noCafC #-}
noCafD :: a -> [Integer]
noCafD _ = trace "hi" (map (+1) $ myEnumFrom 0 1)
{-# NOINLINE noCafD #-}
myEnumFrom :: a -> Integer -> [Integer]
myEnumFrom _ n =  enumFrom n
{-# NOINLINE myEnumFrom #-}

main :: IO ()
main = do
  putStrLn "cafA"
  print $ (cafA !! 1 + cafA !! 2)
  putStrLn "noCafB"
  print $ (noCafB 0 !! 1 + noCafB 0 !! 2)
  putStrLn "noCafC"
  print $ (noCafC 0 !! 1 + noCafC 0 !! 2)
  putStrLn "noCafD"
  print $ (noCafD 0 !! 1 + noCafD 0 !! 2)

Result with -O2

$ stack ghc -- --version
The Glorious Glasgow Haskell Compilation System, version 7.10.3

$ stack ghc -- -O2 cafTest.hs
[1 of 1] Compiling Main             ( cafTest.hs, cafTest.o )
Linking cafTest ...
$ ./cafTest
cafA
hi
7
noCafB
7
noCafC
7
noCafD
hi
7

Result with -O0

$ stack ghc -- -O0 cafTest.hs
[1 of 1] Compiling Main             ( cafTest.hs, cafTest.o )
Linking cafTest ...
$ ./cafTest
cafA
hi
7
noCafB
hi
hi
7
noCafC
hi
hi
7
noCafD
hi
hi
7

I've also tried without trace but results was same. under -O2, I found that the result of incInt function is shared by inspecting profiling output. Why this behaviour?

incIntOrg :: [Integer]
incInt = map (+1) [1..]

incInt :: a -> [Integer]  -- results IS shared. should it be?
incInt _ = map (+1) $ myEnum 0 1
{-# NOINLINE incInt #-}
myEnum :: a -> Integer -> [Integer]
myEnum _ n =  enumFrom n
{-# NOINLINE myEnum #-}
main :: IO ()
main = do
  print (incInt 0 !!  9999999)
  print (incInt 0 !!  9999999)
  print (incInt 0 !!  9999999)

Any comments will be appreciated deeply. Thanks.

Community
  • 1
  • 1
Chul-Woong Yang
  • 1,223
  • 10
  • 17
  • 3
    Usually, CAFs are _desired_, so, yes, it makes sense if GHC sometimes optimises them in. Avoiding them only makes sense in some memory-intensive applications. Have you tried this with something more RAM-heavy? – leftaroundabout Jun 15 '16 at 00:23
  • Oh, then is there any idiomatic ways to prevent CAFs? Mr. Don Stewart's answer (http://stackoverflow.com/questions/6090932/how-to-make-a-caf-not-a-caf-in-haskell) and Mr. Chris Allen's book (http://haskellbook.com/) suggests making CAFs to function with dummy argument is THAT way. But the result with current (v7.10) GHC shows that the method does not work with `-O2`. My context is in 'studying' CAFs of Haskell. – Chul-Woong Yang Jun 15 '16 at 03:32
  • Have you tried https://hackage.haskell.org/package/ghc-dup? – phadej Jun 16 '16 at 18:04

0 Answers0