[英]Haskell laziness question with head function
信息:
在文檔和教程中,它說:默認情況下,“ Haskell很懶”。
他們沒有解釋有關細節,我想知道。
現在我知道如果我寫:
filter odd [1, 2, 3]
在結果顯示或在表達式中使用之前,它不會過濾結果。
我對此有兩個問題:
head
功能懶惰嗎?
如果不是,那為什么不偷懶呢?
如果很懶,Haskell編譯器如何知道何時執行該函數?
我舉一個例子:
f a b = head a + head b
f [2, 3] [4, 5]
在這種情況下,從我的角度來看,頭部將不會返回2 + 4。
它將返回某些類型或函數,稍后將在需要時執行。 (如果我在某個地方弄錯了,請糾正我)。
所以我的建議是,當Haskell看到類似“ +”的操作時,它將計算結果。
但這變得更加復雜,因為對於整數,我想如果我寫3 + 5
話,它也可以是惰性的。
我懷疑在懶惰的表達式開始計算時是否存在帶有函數的列表,因為很難編寫所有變體。
最后:
f head [1, 2]
可以說,在f
函數中,我打印傳遞的變量的類型。
現在,Haskell將如何知道應該傳遞Int 1還是惰性表達式?
謝謝
我認為這里有些混亂,因為有時在兩種不同的情況下使用“懶惰”一詞。
關於懶惰與渴望的語義:考慮以下表達式
(\x -> 42) (error "urk!")
當對以上進行評估時,結果是什么?
根據熱切的語義,我們在調用函數之前先評估參數。 結果將是運行時錯誤。
根據惰性語義,我們立即調用該函數。 該過程可以在操作上和符號上理解如下。
從操作上講 ,它傳遞了thunk ,它是一個對象,它描述尚未評估的參數,並且在需要參數x
時將“強制”(評估)該對象。 我們可以假裝x
指向未error "urk!"
表達式error "urk!"
,將在需要x
時進行評估。
從符號上講,我們使用數學技巧:我們使用稱為“底部”的特殊值來表示錯誤,並稱該error "urk!"
具有這樣的最低價值。 然后,我們簡單地假裝可以傳遞這個非凡的價值。 在上面的函數調用中, x
將綁定到“底部”,就好像它是一個正常值一樣。 可以說這很簡單,因為我們不需要關注表達式的求值方式,而只需關注底部的傳播方式。
更准確地說,我們讓“底部”代表運行時錯誤和非終止(無限遞歸),這兩者都使程序擺脫了返回實際結果的麻煩。
例如,我們有一個if bottom then .. else ..
,那if bottom then .. else ..
總會產生底部。 同樣適用於bottom + 4
(即bottom)。 再次, case bottom of SomeConstructor -> ...; ...
case bottom of SomeConstructor -> ...; ...
是最下面的(嗯,除了newtypes
,但是我們忽略它)。 相反f bottom
可能會或可能不會按照什么是底部f
做:如果它需要的參數,其結果將是底部。
關於惰性(非嚴格)功能。 如果f bottom
是bottom,則有時將函數f
稱為“惰性”(或更恰當地說,是非嚴格的)。
例如:
f x = x+1 -- strict / non lazy
f x = 5 -- non strict / lazy
head xs = case xs of -- strict / non lazy
[] -> error "head: empty list"
(x:xs) -> x
g x = (x,True) -- non strict / lazy
因此,因為head bottom
是作為case bottom of ...
底部,所以head
不懶惰。 在操作上,由於head
在產生結果之前要求其論點,因此它是嚴格/非惰性的。
關於g
:惰性語義的主要特征是像對構造函數(,)
這樣的data
構造函數本質上是惰性的。 也就是說(bottom, 4)
與bottom不同:即使第一對分量是“錯誤”值snd (bottom, 4) = 4
也可以使snd (bottom, 4) = 4
。
因此, g bottom = (bottom, True)
不是底部,我們可以應用snd
提取True
而不觸發錯誤。
head
功能懶惰嗎?
是的,Haskell在默認情況下會延遲評估。
如果很懶,Haskell編譯器如何知道何時執行該函數?
當需要該值時,將對函數進行評估-據我了解,最終會在您以某種方式涉及IO
時發生。
在這種情況下,從我的角度來看,頭部將不會返回2 + 4。
正確,返回的“值”是所謂的thunk ,這是尚未求值的表達式的另一個名稱。 什么意思 是head a + head b
。
懶惰評估規則的主要例外是IO
,它很受評估。 因此,如果您想打印調用f [2, 3] [4, 5]
,那么將對足夠多的表達式求值以產生要打印的結果。
如果需要,有一些方法可以強制更早進行評估,例如通過使用seq
。 這有時可能很重要,因為這些重擊可能會變大。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.