简体   繁体   English

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

[英]Haskell : Will GHC optimize this?

Can GHC simplify id = (\\(a, b) -> (a, b)).(\\(a, b) -> (a, b)) into id = \\(a, b) -> (a, b) ? GHC可以将id = (\\(a, b) -> (a, b)).(\\(a, b) -> (a, b))简化为id = \\(a, b) -> (a, b)

What about more complicated case : 更复杂的情况呢?

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

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

Will GHC simplify id . map GHC会简化id . map id . map into map ? id . mapmap

I tried to use plain beta reduction but it looks like these terms are irreducible because of the nasty pattern matching. 我尝试使用普通的beta缩减,但看起来这些术语是不可简化的,因为讨厌的模式匹配。

Therefore I am curious how do GHC's optimization techniques deal with that. 因此,我很好奇GHC的优化技术是如何处理的。

You can ask these questions of ghc by running it with -ddump-simpl . 您可以通过使用-ddump-simpl运行它来询问ghc的这些问题。 This will cause ghc to dump the "core" code that it compiles programs into. 这将导致ghc转储它编译程序的“核心”代码。 Core is an intermediate language between the part of the compiler that reasons about Haskell code and the part of the compiler that transforms that code into machine code. Core是编译器的一部分介于Haskell代码之间的中间语言,也是编译器将该代码转换为机器代码的部分。

When I compiled the following with -O2 -ddump-simpl the results surprised me. 当我使用-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))

The resulting core for tupid1 makes a new specialized identity function. 由此产生的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

In core the polymorphic type arguments to functions are represented as explicit arguments. 在核心中,函数的多态类型参数表示为显式参数。 tupid1 takes two of these type arguments, named a_ayd and b_aye , for the two type variables a and b in its signature. tupid1为其签名中的两个类型变量ab采用其中两个类型参数,名为a_aydb_aye It also takes a term ds_dIl that has the type of a tuple of those two types ( ds_dIl :: (a_ayd, b_aye) ) and returns it unmodified. 它还需要一个术语ds_dIl ,它具有这两种类型的元组类型( ds_dIl :: (a_ayd, b_aye) )并且不加修改地返回它。

The surprising result is tupid2 ... 令人惊讶的结果是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

... which ghc simplifies to tupid1 ! ...哪个ghc简化为tupid1 How it deduces that is beyond my immediate knowledge or ability to discover. 如何推断这是超出我的直接知识或发现的能力。


The identity example for Maybe Maybe的标识示例

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

Is also simplified to an identity function with no pattern matching 也简化为没有模式匹配的身份函数

-- 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

The core for map for Maybe isn't interesting for this question 对于这个问题, Maybe map核心并不有意思

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

But if it's composed with maybeid 但如果它是由maybeid组成的

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

ghc simplifies it to maybemap 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

And it does the same thing if id is composed with f . 如果idf组成,它也会做同样的事情。

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

The composition with the identity function is removed and the whole function simplifies to maybemap 删除具有身份功能的组合,整个功能简化为可能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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM