Haskell совместное использование: определяется ли то, что передается при компиляции кода? - PullRequest
0 голосов
/ 03 февраля 2020

У меня есть вопрос относительно совместного использования в 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

1 Ответ

1 голос
/ 04 февраля 2020

Было бы довольно шокирующим, если бы GH C "заметил" дублированный аргумент и исключил его для вас. Такой анализ глазков технически невозможен, но зачастую он обходится вам гораздо дороже, чем выгода. Представьте, что у вас есть

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