簡體   English   中英

為什么這個Haskell語句不能懶惰地評估?

[英]Why does this Haskell statement not evaluate lazily?

我定義了以下函數:

ex 1 x = 1
ex 0 x = 0
ex b x = b ** x

然后,當我執行以下操作時:

1 `ex` (sum [1..])

它試圖計算無限序列的總和,而不是懶惰和返回1.為什么?


編輯:經過進一步調查,我發現如果我在文件中定義ex函數會發生懶惰,但如果我在GHCI中定義它則不會:

$ ghci
GHCi, version 6.8.2: http://www.haskell.org/ghc/  :? for help
Loading package base ... linking ... done.
Prelude> let ex 1 x = 1
Prelude> let ex b x = b ** x
Prelude> ex 1 (sum [1..])
<interactive>: out of memory (requested 1048576 bytes)

如果我將ex定義拉入文件(在本例中為test.hs):

$ ghci
GHCi, version 6.8.2: http://www.haskell.org/ghc/  :? for help
Loading package base ... linking ... done.
Prelude> :load test.hs 
[1 of 1] Compiling Main             ( test.hs, interpreted )
Ok, modules loaded: Main.
*Main> ex 1 (sum [1..])
1.0

那么,新問題是為什么?

在GHCi中,每個let語句都引入了ex定義,而不是您期望的多個模式案例。 所以它掛起是因為,當你之后輸入ex 1 (sum [1..]) ,只存在最終的ex bx = b ** x版本。

如果要在GHCi中定義具有多個模式案例的函數,則需要將其放在單個let語句中,如下所示:

let ex 1 x = 1; ex 0 x = 0; ex b x = b ** x

這同樣適用於其他任何東西,通常會在多個線路,如被寫do記號。 例如,這樣的函數:

f x = do
    y <- get
    put (x + y)
    return y

必須在GHCi中這樣寫:

let f x = do { y <- get; put (x + y); return y }
Prelude> let ex 1 x = 1
Prelude> let ex b x = b ** x

你沒有在這里定義一個包含兩種情況的函數。 您可以使用一個案例定義一個函數,然后再次定義它,覆蓋先前的定義。

要使用兩個模式定義一個函數,請使用let ex 1 x = 1; ex bx = b ** x let ex 1 x = 1; ex bx = b ** x ,即用分號分隔案例。

我錯過了一點懶惰,這使得答案低於假。


因為sum計算序列中所有元素的總和。 在你的情況下,這是無止境的。

你可能想要

map ((curry ex) 1) [1..]

那是

map -- map each item x to y
    (
        (
            curry ex -- curry ex, to transform (x, y) -> z into x -> y -> z
        )
        1 -- then invoke it with 1, which results in y -> z, x being 1
    )
    [1..] -- the infinite sequence to be mapped.

暫無
暫無

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

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