2017-05-15 38 views
4

GHC能否將id = (\(a, b) -> (a, b)).(\(a, b) -> (a, b))簡化爲id = \(a, b) -> (a, b)Haskell:GHC會優化嗎?

有關更復雜的情況是什麼:

id (Just x) = Just x 
id Nothing = Nothing 

map f (Just x) = Just (f x) 
map _ Nothing = Nothing 

將GHC簡化id . mapmap

我試圖使用簡單的beta縮減,但由於討厭的模式匹配,它看起來像這些術語是不可約的。

因此,我很好奇GHC的優化技術如何處理這個問題。

回答

12

你可我用儲存系統-ddump-simpl也可以這樣問這些關於ghc的問題。這將導致ghc轉儲它編譯程序的「核心」代碼。 Core是編譯器部分之間的一種中間語言,其原因在於Haskell代碼和編譯器將代碼轉換爲機器代碼的部分。

當我用-O2 -ddump-simpl編譯以下內容時,結果令我感到驚訝。

tupid1 :: (a, b) -> (a, b) 
tupid1 = (\(a, b) -> (a, b)) 

tupid2 :: (a, b) -> (a, b) 
tupid2 = (\(a, b) -> (a, b)) . (\(a, b) -> (a, b)) 

由此產生的tupid1的核心產生了新的專用身份函數。

-- RHS size: {terms: 4, types: 7, coercions: 0} 
tupid1 :: forall a_aqo b_aqp. (a_aqo, b_aqp) -> (a_aqo, b_aqp) 
[GblId, 
Arity=1, 
Caf=NoCafRefs, 
Str=DmdType <S,1*U(U,U)>m, 
Unf=Unf{Src=InlineStable, TopLvl=True, Value=True, ConLike=True, 
     WorkFree=True, Expandable=True, 
     Guidance=ALWAYS_IF(arity=1,unsat_ok=True,boring_ok=True) 
     Tmpl= \ (@ a_ayd) 
       (@ b_aye) 
       (ds_dIl [Occ=Once] :: (a_ayd, b_aye)) -> 
       ds_dIl}] 
tupid1 = \ (@ a_ayd) (@ b_aye) (ds_dIl :: (a_ayd, b_aye)) -> ds_dIl 

在覈心中,函數的多態類型參數被表示爲顯式參數。 tupid1在其簽名中對於兩個類型變量ab取兩個這樣的類型參數,名爲a_aydb_aye。它還需要一個術語ds_dIl,它具有這兩種類型的元組的類型(ds_dIl :: (a_ayd, b_aye)),並且未修改地返回它。

令人驚訝的結果是tupid2 ...

-- RHS size: {terms: 1, types: 0, coercions: 0} 
tupid2 :: forall a_aqm b_aqn. (a_aqm, b_aqn) -> (a_aqm, b_aqn) 
[GblId, 
Arity=1, 
Caf=NoCafRefs, 
Str=DmdType <S,1*U(U,U)>m, 
Unf=Unf{Src=InlineStable, TopLvl=True, Value=True, ConLike=True, 
     WorkFree=True, Expandable=True, 
     Guidance=ALWAYS_IF(arity=1,unsat_ok=True,boring_ok=True) 
     Tmpl= \ (@ a_axZ) (@ b_ay0) (x_aIw [Occ=Once] :: (a_axZ, b_ay0)) -> 
       x_aIw}] 
tupid2 = tupid1 

...這GHC簡化爲tupid1!它如何演繹超出了我的直接知識或發現能力。


Maybe

maybeid :: Maybe a -> Maybe a 
maybeid (Just x) = Just x 
maybeid Nothing = Nothing 

身份示例也簡化爲一個標識功能,沒有模式匹配

-- RHS size: {terms: 3, types: 4, coercions: 0} 
maybeid :: forall a_aqn. Maybe a_aqn -> Maybe a_aqn 
[GblId, 
Arity=1, 
Caf=NoCafRefs, 
Str=DmdType <S,1*U>, 
Unf=Unf{Src=InlineStable, TopLvl=True, Value=True, ConLike=True, 
     WorkFree=True, Expandable=True, 
     Guidance=ALWAYS_IF(arity=1,unsat_ok=True,boring_ok=True) 
     Tmpl= \ (@ a_aqI) (ds_dIq [Occ=Once] :: Maybe a_aqI) -> ds_dIq}] 
maybeid = \ (@ a_aqI) (ds_dIq :: Maybe a_aqI) -> ds_dIq 

mapMaybe的核心是不是這個有趣的問題

maybemap :: (a -> b) -> Maybe a -> Maybe b 
maybemap f (Just x) = Just (f x) 
maybemap _ Nothing = Nothing 

但是,如果它與maybeid

maybeidmap :: (a -> b) -> Maybe a -> Maybe b 
maybeidmap f = maybeid . maybemap f 

GHC組成它簡化爲maybemap

-- RHS size: {terms: 1, types: 0, coercions: 0} 
maybeidmap 
    :: forall a_aqp b_aqq. 
    (a_aqp -> b_aqq) -> Maybe a_aqp -> Maybe b_aqq 
[GblId, 
Arity=2, 
Caf=NoCafRefs, 
Str=DmdType <L,1*C1(U)><S,1*U>, 
Unf=Unf{Src=InlineStable, TopLvl=True, Value=True, ConLike=True, 
     WorkFree=True, Expandable=True, 
     Guidance=ALWAYS_IF(arity=0,unsat_ok=True,boring_ok=True) 
     Tmpl= maybemap}] 
maybeidmap = maybemap 

而且它如果id由具有f同樣的事情。

maybemapid :: (a -> b) -> Maybe a -> Maybe b 
maybemapid f = maybemap (id . f) 

與身份機能的組合物被移除並且整個函數可簡化爲maybemap

-- RHS size: {terms: 1, types: 0, coercions: 0} 
maybemapid 
    :: forall a_aqq b_aqr. 
    (a_aqq -> b_aqr) -> Maybe a_aqq -> Maybe b_aqr 
[GblId, 
Arity=2, 
Caf=NoCafRefs, 
Str=DmdType <L,1*C1(U)><S,1*U>, 
Unf=Unf{Src=InlineStable, TopLvl=True, Value=True, ConLike=True, 
     WorkFree=True, Expandable=True, 
     Guidance=ALWAYS_IF(arity=2,unsat_ok=True,boring_ok=False) 
     Tmpl= \ (@ a_ar2) 
       (@ b_ar3) 
       (f_aqL [Occ=Once!] :: a_ar2 -> b_ar3) 
       (eta_B1 [Occ=Once!] :: Maybe a_ar2) -> 
       case eta_B1 of _ [Occ=Dead] { 
        Nothing -> GHC.Base.Nothing @ b_ar3; 
        Just x_aqJ [Occ=Once] -> GHC.Base.Just @ b_ar3 (f_aqL x_aqJ) 
       }}] 
maybemapid = maybemap