この記事によると、
GHCに関する限り、列挙型は単一のコンストラクター型としてカウントされないため、厳密なコンストラクターフィールドまたは厳密な関数引数として使用された場合、列挙型はアンパックの恩恵を受けません。これは GHC の欠陥ですが、回避できます。
代わりに、newtypes の使用が推奨されます。ただし、次のコードではこれを確認できません。
{-# LANGUAGE MagicHash,BangPatterns #-}
{-# OPTIONS_GHC -O2 -funbox-strict-fields -rtsopts -fllvm -optlc --x86-asm-syntax=intel #-}
module Main(main,f,g)
where
import GHC.Base
import Criterion.Main
data D = A | B | C
newtype E = E Int deriving(Eq)
f :: D -> Int#
f z | z `seq` False = 3422#
f z = case z of
A -> 1234#
B -> 5678#
C -> 9012#
g :: E -> Int#
g z | z `seq` False = 7432#
g z = case z of
(E 0) -> 2345#
(E 1) -> 6789#
(E 2) -> 3535#
f' x = I# (f x)
g' x = I# (g x)
main :: IO ()
main = defaultMain [ bench "f" (whnf f' A)
, bench "g" (whnf g' (E 0))
]
アセンブリを見ると、列挙型 D の各コンストラクターのタグは実際にはアンパックされ、命令に直接ハードコーディングされています。さらに、この関数f
にはエラー処理コードがなく、より 10% 以上高速ですg
。より現実的なケースでは、列挙型を newtype に変換した後にスローダウンも経験しました。誰かが私にこれについての洞察を与えることができますか? ありがとう。