如果我有一个像main = print ( (+) <$> Just 1 <*> Just 2 )
编译器将决定减少不依赖IO
的程序部分吗( (+) <$> Just 1 <*> Just 2 ) => (Just 3)
?
还是程序仍然从(+) <$> Just 1
创建新功能,然后在运行时将其应用于Just 2
?
最佳答案
让我们问GHC!
% echo 'main = print ((+) <$> Just 1 <*> Just 2)' > test.hs
% ghc -O2 -ddump-simpl test.hs
[1 of 1] Compiling Main ( test.hs, test.o )
==================== Tidy Core ====================
Result size of Tidy Core
= {terms: 42, types: 47, coercions: 9, joins: 0/0}
-- RHS size: {terms: 1, types: 0, coercions: 0, joins: 0/0}
Main.main4 :: Integer
[GblId,
Caf=NoCafRefs,
Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True,
WorkFree=True, Expandable=True, Guidance=IF_ARGS [] 100 0}]
Main.main4 = 3
-- RHS size: {terms: 9, types: 11, coercions: 0, joins: 0/0}
Main.main3 :: [Char]
[GblId,
Unf=Unf{Src=<vanilla>, TopLvl=True, Value=False, ConLike=False,
WorkFree=False, Expandable=False, Guidance=IF_ARGS [] 60 30}]
Main.main3
= case GHC.Show.$w$cshowsPrec4 11# Main.main4 (GHC.Types.[] @ Char)
of
{ (# ww3_a23H, ww4_a23I #) ->
GHC.Types.: @ Char ww3_a23H ww4_a23I
}
-- RHS size: {terms: 3, types: 1, coercions: 0, joins: 0/0}
Main.main2 :: [Char]
[GblId,
Unf=Unf{Src=<vanilla>, TopLvl=True, Value=False, ConLike=False,
WorkFree=False, Expandable=False, Guidance=IF_ARGS [] 30 0}]
Main.main2 = ++ @ Char GHC.Show.$fShowMaybe1 Main.main3
-- RHS size: {terms: 4, types: 0, coercions: 0, joins: 0/0}
Main.main1
:: GHC.Prim.State# GHC.Prim.RealWorld
-> (# GHC.Prim.State# GHC.Prim.RealWorld, () #)
[GblId,
Arity=1,
Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True,
WorkFree=True, Expandable=True, Guidance=IF_ARGS [] 40 60}]
Main.main1
= GHC.IO.Handle.Text.hPutStr2
GHC.IO.Handle.FD.stdout Main.main2 GHC.Types.True
-- RHS size: {terms: 1, types: 0, coercions: 3, joins: 0/0}
main :: IO ()
[GblId,
Arity=1,
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= Main.main1
`cast` (Sym (GHC.Types.N:IO[0] <()>_R)
:: ((GHC.Prim.State# GHC.Prim.RealWorld
-> (# GHC.Prim.State# GHC.Prim.RealWorld, () #)) :: *)
~R#
(IO () :: *))}]
main
= Main.main1
`cast` (Sym (GHC.Types.N:IO[0] <()>_R)
:: ((GHC.Prim.State# GHC.Prim.RealWorld
-> (# GHC.Prim.State# GHC.Prim.RealWorld, () #)) :: *)
~R#
(IO () :: *))
-- RHS size: {terms: 2, types: 1, coercions: 3, joins: 0/0}
Main.main5
:: GHC.Prim.State# GHC.Prim.RealWorld
-> (# GHC.Prim.State# GHC.Prim.RealWorld, () #)
[GblId,
Arity=1,
Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True,
WorkFree=True, Expandable=True, Guidance=IF_ARGS [] 20 60}]
Main.main5
= GHC.TopHandler.runMainIO1
@ ()
(Main.main1
`cast` (Sym (GHC.Types.N:IO[0] <()>_R)
:: ((GHC.Prim.State# GHC.Prim.RealWorld
-> (# GHC.Prim.State# GHC.Prim.RealWorld, () #)) :: *)
~R#
(IO () :: *)))
-- RHS size: {terms: 1, types: 0, coercions: 3, joins: 0/0}
:Main.main :: IO ()
[GblId,
Arity=1,
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= Main.main5
`cast` (Sym (GHC.Types.N:IO[0] <()>_R)
:: ((GHC.Prim.State# GHC.Prim.RealWorld
-> (# GHC.Prim.State# GHC.Prim.RealWorld, () #)) :: *)
~R#
(IO () :: *))}]
:Main.main
= Main.main5
`cast` (Sym (GHC.Types.N:IO[0] <()>_R)
:: ((GHC.Prim.State# GHC.Prim.RealWorld
-> (# GHC.Prim.State# GHC.Prim.RealWorld, () #)) :: *)
~R#
(IO () :: *))
-- RHS size: {terms: 1, types: 0, coercions: 0, joins: 0/0}
Main.$trModule4 :: GHC.Prim.Addr#
[GblId,
Caf=NoCafRefs,
Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True,
WorkFree=True, Expandable=True, Guidance=IF_ARGS [] 20 0}]
Main.$trModule4 = "main"#
-- RHS size: {terms: 2, types: 0, coercions: 0, joins: 0/0}
Main.$trModule3 :: GHC.Types.TrName
[GblId,
Caf=NoCafRefs,
Str=m1,
Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True,
WorkFree=True, Expandable=True, Guidance=IF_ARGS [] 10 20}]
Main.$trModule3 = GHC.Types.TrNameS Main.$trModule4
-- RHS size: {terms: 1, types: 0, coercions: 0, joins: 0/0}
Main.$trModule2 :: GHC.Prim.Addr#
[GblId,
Caf=NoCafRefs,
Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True,
WorkFree=True, Expandable=True, Guidance=IF_ARGS [] 20 0}]
Main.$trModule2 = "Main"#
-- RHS size: {terms: 2, types: 0, coercions: 0, joins: 0/0}
Main.$trModule1 :: GHC.Types.TrName
[GblId,
Caf=NoCafRefs,
Str=m1,
Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True,
WorkFree=True, Expandable=True, Guidance=IF_ARGS [] 10 20}]
Main.$trModule1 = GHC.Types.TrNameS Main.$trModule2
-- RHS size: {terms: 3, types: 0, coercions: 0, joins: 0/0}
Main.$trModule :: GHC.Types.Module
[GblId,
Caf=NoCafRefs,
Str=m,
Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True,
WorkFree=True, Expandable=True, Guidance=IF_ARGS [] 10 30}]
Main.$trModule = GHC.Types.Module Main.$trModule3 Main.$trModule1
Linking test ...
与往常一样,核心有点冗长。当我尝试阅读时,请允许我向您展示一些眼动跟踪。
:Main.main
= Main.main5
`cast` ...
Main.main5
= ...runMainIO1 ... (Main.main1 `cast` ...)
Main.main1
= ...hPutStr2 ...stdout Main.main2 ...
Main.main2 = ++ ...fShowMaybe1 Main.main3
Main.main3
= case ...showsPrec4 11# Main.main4 ...
of
{- after a bit of squinting... -}
x -> x
Main.main4 = 3
在我看来,该
3
看起来很像1+2
。对于偏执狂,我尝试将1
和2
替换为10
和20
,的确看到了底部带有30
的类似结构。因此,看起来很有说服力的证据表明它在编译时进行了此计算。就是说,我希望这很可能是针对简单数字类型的数字计算所特有的。更多令人兴奋的类型的编译时计算具有一个奇怪而令人困惑的时空折衷,而处理这种情况的通常方法是让程序员尽可能多地对其进行控制。
关于haskell - GHC是否会在编译时减少不依赖IO的表达式?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/49363198/