首页 > 解决方案 > Haskell 共享:代码编译时是否确定共享什么?

问题描述

我有一个关于在 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

标签: haskellsharing

解决方案


如果 GHC “注意到​​”重复的论点并为您消除它,那将是非常令人震惊的。这种窥视孔分析在技术上并非不可能,但它最终往往会让您付出比获得更多的成本。想象一下你有

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

推荐阅读