Haskell sharing : 代码编译的时候就决定共享什么了吗?
Haskell sharing : Is it determined what is shared when the code is compiled?
我有一个关于在 haskell(一种函数式编程语言)中共享的问题。
给出
f n | n > 0 = n
我对如何逐步计算以下表达式感兴趣。是吗:
f (2*3) + f 6 = f 6 + f 6 = 6 + 6 = 12
或者是:
f (2*3) + f 6 = f 6 + f 6 = 6 + f 6 = 6 + 6 = 12
如果 GHC "noticed" 重复的参数并为您删除它,那将是非常令人震惊的。这种窥孔分析在技术上并非不可能,但它最终往往会让你付出的代价远远超过它的收获。想象一下你有
g x = f x + f 6
如果编译器想避免对 f
的过度调用,它可以每次检查是否 x == 6
,如果是,则共享结果。但大多数时候 x /= 6
,所以这个额外的检查会浪费你的时间。如果您认为优化会经常触发而有用,您当然可以自己做。
我还查看了 -ddump-simpl
的输出,以观察 GHCI 生成的核心。我相信这个输出是在所有优化步骤 运行 之后,所以这将是一个明确的答案,至少在 GHCI 中,这个优化没有被执行;但是,我不确定这一点。
注意这里有两次无条件调用f
。
$ ghci -ddump-simpl
...
Prelude> f (2 * 3) + f 6
==================== Simplified expression ====================
let {
it_a2Cx :: forall a. (GHC.Num.Num a, GHC.Classes.Ord a) => a
[LclId,
Arity=2,
Unf=Unf{Src=<vanilla>, TopLvl=False, Value=True, ConLike=True,
WorkFree=True, Expandable=True, Guidance=IF_ARGS [150 0] 550 0}]
it_a2Cx
= \ (@ a_a2Yl)
($dNum_a2YF :: GHC.Num.Num a_a2Yl)
($dOrd_a2YG :: GHC.Classes.Ord a_a2Yl) ->
GHC.Num.+
@ a_a2Yl
$dNum_a2YF
(Ghci1.f
@ a_a2Yl
$dOrd_a2YG
$dNum_a2YF
(GHC.Num.*
@ a_a2Yl
$dNum_a2YF
(GHC.Num.fromInteger @ a_a2Yl $dNum_a2YF 2)
(GHC.Num.fromInteger @ a_a2Yl $dNum_a2YF 3)))
(Ghci1.f
@ a_a2Yl
$dOrd_a2YG
$dNum_a2YF
(GHC.Num.fromInteger @ a_a2Yl $dNum_a2YF 6)) } in
GHC.Base.thenIO
@ ()
@ [()]
(System.IO.print
@ GHC.Integer.Type.Integer
GHC.Show.$fShowInteger
(it_a2Cx
@ GHC.Integer.Type.Integer
GHC.Num.$fNumInteger
GHC.Integer.Type.$fOrdInteger))
(GHC.Base.returnIO
@ [()]
(GHC.Types.:
@ ()
(it_a2Cx
`cast` (UnsafeCo representational (forall a.
(GHC.Num.Num a, GHC.Classes.Ord a) =>
a) ()
:: (forall a. (GHC.Num.Num a, GHC.Classes.Ord a) => a :: *)
~R# (() :: *)))
(GHC.Types.[] @ ())))
12
我有一个关于在 haskell(一种函数式编程语言)中共享的问题。
给出
f n | n > 0 = n
我对如何逐步计算以下表达式感兴趣。是吗:
f (2*3) + f 6 = f 6 + f 6 = 6 + 6 = 12
或者是:
f (2*3) + f 6 = f 6 + f 6 = 6 + f 6 = 6 + 6 = 12
如果 GHC "noticed" 重复的参数并为您删除它,那将是非常令人震惊的。这种窥孔分析在技术上并非不可能,但它最终往往会让你付出的代价远远超过它的收获。想象一下你有
g x = f x + f 6
如果编译器想避免对 f
的过度调用,它可以每次检查是否 x == 6
,如果是,则共享结果。但大多数时候 x /= 6
,所以这个额外的检查会浪费你的时间。如果您认为优化会经常触发而有用,您当然可以自己做。
我还查看了 -ddump-simpl
的输出,以观察 GHCI 生成的核心。我相信这个输出是在所有优化步骤 运行 之后,所以这将是一个明确的答案,至少在 GHCI 中,这个优化没有被执行;但是,我不确定这一点。
注意这里有两次无条件调用f
。
$ ghci -ddump-simpl
...
Prelude> f (2 * 3) + f 6
==================== Simplified expression ====================
let {
it_a2Cx :: forall a. (GHC.Num.Num a, GHC.Classes.Ord a) => a
[LclId,
Arity=2,
Unf=Unf{Src=<vanilla>, TopLvl=False, Value=True, ConLike=True,
WorkFree=True, Expandable=True, Guidance=IF_ARGS [150 0] 550 0}]
it_a2Cx
= \ (@ a_a2Yl)
($dNum_a2YF :: GHC.Num.Num a_a2Yl)
($dOrd_a2YG :: GHC.Classes.Ord a_a2Yl) ->
GHC.Num.+
@ a_a2Yl
$dNum_a2YF
(Ghci1.f
@ a_a2Yl
$dOrd_a2YG
$dNum_a2YF
(GHC.Num.*
@ a_a2Yl
$dNum_a2YF
(GHC.Num.fromInteger @ a_a2Yl $dNum_a2YF 2)
(GHC.Num.fromInteger @ a_a2Yl $dNum_a2YF 3)))
(Ghci1.f
@ a_a2Yl
$dOrd_a2YG
$dNum_a2YF
(GHC.Num.fromInteger @ a_a2Yl $dNum_a2YF 6)) } in
GHC.Base.thenIO
@ ()
@ [()]
(System.IO.print
@ GHC.Integer.Type.Integer
GHC.Show.$fShowInteger
(it_a2Cx
@ GHC.Integer.Type.Integer
GHC.Num.$fNumInteger
GHC.Integer.Type.$fOrdInteger))
(GHC.Base.returnIO
@ [()]
(GHC.Types.:
@ ()
(it_a2Cx
`cast` (UnsafeCo representational (forall a.
(GHC.Num.Num a, GHC.Classes.Ord a) =>
a) ()
:: (forall a. (GHC.Num.Num a, GHC.Classes.Ord a) => a :: *)
~R# (() :: *)))
(GHC.Types.[] @ ())))
12