1

CAF(リソース共有)を避けるため、仮引数付きの関数に変換してみましたが、成功しませんでした(noCafB)。How to make a CAF not a CAF in Haskell? を読みました。で試しnoCafCてみnoCafDました。でコンパイルすると -O0、仮引数を持つ関数は毎回評価されました。しかし では、-O2GHC はそれらの関数を CAF に変換するようです。これは意図した動作 (GHC の最適化) ですか?

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)

での結果-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

での結果-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

なしでも試しましtraceたが、結果は同じでした。の下で、プロファイリング出力を調べると、関数-O2の結果が共有されていることがわかりました。incIntなぜこの振る舞いをするのですか?

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)

コメントをお待ちしております。ありがとう。

4

0 に答える 0