Haskell:GHC会对此进行优化吗?

For*_* O. 4 haskell ghc

GHC可以简化id = (\(a, b) -> (a, b)).(\(a, b) -> (a, b))id = \(a, b) -> (a, b)

更复杂的情况呢?

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

map f (Just x) = Just (f x)
map _ Nothing  = Nothing
Run Code Online (Sandbox Code Playgroud)

GHC会简化id . mapmap

我试图使用普通的beta缩减,但看起来这些术语是不可简化的,因为讨厌的模式匹配.

因此,我很好奇GHC的优化技术是如何处理的.

Cir*_*dec 12

您可以通过运行它来询问ghc的这些问题-ddump-simpl.这将导致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))
Run Code Online (Sandbox Code Playgroud)

由此产生的核心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
Run Code Online (Sandbox Code Playgroud)

在核心中,函数的多态类型参数表示为显式参数.tupid1有两个的这些类型参数,命名a_aydb_aye,两个类型变量a,并b在其签名.它还需要一个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
Run Code Online (Sandbox Code Playgroud)

... ghc简化为tupid1!如何推断这是超出我的直接知识或发现的能力.


的标识示例 Maybe

maybeid :: Maybe a -> Maybe a
maybeid (Just x) = Just x
maybeid Nothing = Nothing
Run Code Online (Sandbox Code Playgroud)

也简化为没有模式匹配的身份函数

-- 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
Run Code Online (Sandbox Code Playgroud)

对于核心mapMaybe是不是这个有趣的问题

maybemap :: (a -> b) -> Maybe a -> Maybe b
maybemap f (Just x) = Just (f x)
maybemap _ Nothing = Nothing
Run Code Online (Sandbox Code Playgroud)

但如果它是由 maybeid

maybeidmap :: (a -> b) -> Maybe a -> Maybe b
maybeidmap f = maybeid . maybemap f
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

如果用id它组成,它也会做同样的事情f.

maybemapid :: (a -> b) -> Maybe a -> Maybe b
maybemapid f = maybemap (id . f)
Run Code Online (Sandbox Code Playgroud)

删除具有同一性功能的组合,整个功能简化为 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
Run Code Online (Sandbox Code Playgroud)