簡體   English   中英

Haskell在多大程度上懶惰?

[英]To what extent is Haskell lazy?

我需要對Haskell的懶惰做一些澄清。

如果我有這個功能:

myFunction arg
  | arg == 1 = a
  | arg == 2 = a*b
  | arg == 3 = b+c
  | otherwise = (a+b)*c
     where
            a = ...
            b = ...
            c = ...
            d = ...

當我調用myFunction 1 ,Haskell將只評估a = ...函數,既不是b也不是c ,也不是d

但如果我寫

myFunction arg
  | arg == 1 = a
  | arg == 2 = a*b
  | arg == 3 = b+c
  | otherwise = (a+b)*c
     where
            (a,b,c,d) = anotherFunction arg

Haskell的行為是什么?

  • 它只評估a並將懶惰“傳播”到anotherFunction嗎?
  • 或者,它會評估整個元組(a,b,c,d)作為anotherFunction結果嗎?

在這兩種情況下,除非要求該值,否則它不會評估任何內容。 苛刻的值的一種方法是在調用該ghci中函數(它打印在值ghci ,因此,要求它)。 假設您正在執行該函數,那么在第二種情況下,它將元組評估為弱頭正規形式(WHNF) ,然后計算(a,b,c,d)的第一個元素,因為只需要該值。 其他元素bcd將采用thunk形式。 事實上,您可以自己驗證:

myFunction arg
  | arg == 1 = a
  | arg == 2 = a*b
  | arg == 3 = b+c
  | otherwise = (a+b)*c
  where
    (a,b,c,d) = anotherFunction arg

anotherFunction x = (x, undefined, undefined, undefined)

演示ghci:

λ> myFunction 1
1

好吧它只對a感興趣,所以這意味着有一個隱含的函數

thea :: (a,b,c,d) -> a
thea (a,_,_,_) = a

換句話說,Haskell對元組的其他元素不感興趣 然而,有時元組的元素共享一些結構。 假設另一個函數定義為:

anotherFunction :: Int -> (Int,Int,Int,Int)
anotherFunction x = (z,t,f,g)
    where f = x*x
          g = f+x
          z = g-2
          t = 3

在這種情況下 - 為了評估第一個元素 - 還將評估第三個和第四個元素。 但由於你不對它們做任何事情,Haskell對它們的結果不會特別感興趣。

正如其他人已經指出的那樣,只有a會進行評估。

但請記住,為了利用懶惰,在評估其組件之前, anotherFunction返回一個元組是至關重要的。 例如,考慮一下

anotherFunction n = if p > 1000 then (n, p) else (n, 0)
  where p = product [1..n]

以上將始終評估product [1..n] ,即使調用者只需要第一對組件(即n )。 這是因為在返回對之前需要評估if ,並強制p 相比之下,

anotherFunction n = (n, if p > 1000 then p else 0)
  where p = product [1..n]

將立即返回該對。 如果僅評估其第一個組件,則根本不會計算p

除非需要獲取該變量的值,否則不會對其進行求值。 基本上Haskell是如此懶惰,除非被告知不是這樣。

您可以像這樣確認一下

Prelude> :set +m
Prelude> let anotherFunction = (100, 1 `div` 0)
Prelude| 
Prelude> let myFunction arg
Prelude|                | arg == 1  = a
Prelude|                | otherwise = b
Prelude|                where
Prelude|                     (a, b) = anotherFunction
Prelude| 

這里, 1 `div` 0將提高divide by zero誤差。 如果它評估所有元素,那么即使你用1調用myFunction ,你也會得到那個錯誤,但是

Prelude> myFunction 1
100

只有當您使用任何其他值調用它時,才需要計算元組的第二個值,並且它將失敗並且divide by zero錯誤。

Prelude> myFunction 2
*** Exception: divide by zero

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM