2011-10-23 192 views
31

我正在消化很好的演示文稿爲什麼學習Haskell?由Keegan McAllister提供的。在那裏,他最後說,minimum在哈斯克爾時間複雜度 O(n)的使用片斷非平凡惰性評估

minimum = head . sort 

爲Haskell的惰性計算的說明。不過,我認爲這個例子本質上是一種學術性的。因此,我要求一個更實際的例子,其中大部分的計算都被拋棄了。

+3

這個例子是學術和懶惰評估的好處是不明顯的。你爲什麼想要後者?僅僅看到現實世界的代碼可以從懶惰評估中受益就足夠了嗎? – delnan

+0

「計算機科學中的所有問題都可以通過另一層間接性來解決」。懶惰也是一種間接。 –

+0

https://www.reddit.com/r/haskell/comments/5xge0v/today_i_used_laziness_for/?limit=500有一堆很好的例子 – unhammer

回答

75
  • 你有沒有寫過AI?難道你不得不通過遍歷樹遍歷修剪信息(例如最大深度,相鄰分支的最小代價或其他這樣的信息)嗎?這意味着每次你想改進你的AI時,你都必須寫一個新的樹遍歷。這是愚蠢的。通過懶惰的評估,這不再是一個問題:編寫樹遍歷函數一次,以產生一個巨大的(甚至可能是無限!)遊戲樹,並讓消費者決定要消耗多少。

  • 編寫一個顯示大量信息的GUI?無論如何,它要快速運行?在其他語言中,您可能必須編寫僅呈現可見場景的代碼。在Haskell中,您可以編寫呈現整個場景的代碼,然後選擇要觀察的像素。同樣,渲染一個複雜的場景?爲什麼不計算不同細節級別的無限序列場景,並在程序運行時選擇最合適的場景?

  • 你寫了一個昂貴的函數,並決定爲了速度而對它進行記憶。在其他語言中,這需要構建一個數據結構,以跟蹤您知道答案的函數的哪些輸入,並在看到新輸入時更新結構。請記住讓它線程安全 - 如果我們真的需要速度,我們也需要並行性!在Haskell中,您構建了一個無限數據結構,併爲每個可能的輸入項輸入條目,並評估與您所關心的輸入相對應的數據結構部分。線程安全免費提供純度。

  • 這是一個可能比以前更平淡一些。你有沒有發現過&&||不是你想要短路的唯一東西?我當然有!例如,我喜歡結合Maybe值的<|>函數:它的第一個參數實際上有一個值。所以Just 3 <|> Nothing = Just 3; Nothing <|> Just 7 = Just 7;和Nothing <|> Nothing = Nothing。而且,它是短路的:如果事實證明它的第一個參數是Just,它不會費心去做出計算第二個參數所需的計算。

    <|>不是內置於該語言;它由圖書館加固。那就是:懶惰允許你寫全新的短路形式。 (事實上​​,在Haskell,甚至(&&)(||)短路行爲沒有內置的編譯器魔術:他們從語言的標準庫語義加上他們的定義中自然產生的。)

一般來說,這裏的共同主題是,你可以將價值的產生與確定哪些值是感興趣的看做分開。這使得事情更加可組合,因爲選擇什麼有趣的東西看起來不需要被製片人知道。

+2

不錯的一點!這些論據非常好。 – fuz

+0

哇,令人信服的論據--- Haskell,恕我直言,前景看好。所以'<|>'運算符相當於(Emacs-)Lisp的'或'對象的行爲,它總是可以是'nil',對嗎?無論如何,我真的很想念其他語言的這種行爲。 –

+0

'thread pruning information'是什麼意思?是某種特定樹的分支表現統計的記錄嗎? –

4

考慮生成並消耗序列的第一個元素的無限個序列。沒有懶惰的評估,幼稚的編碼會在生成步驟中永遠運行,並且永遠不會消耗任何東西。通過懶惰的評估,只有代碼試圖消耗的元素纔會生成。

7

這是我昨天發佈到另一個線程的着名示例。漢明數字是沒有任何主要因素大於5的數字。他們有形式2^i * 3^j * 5^k。它們的前20個是:

[1,2,3,4,5,6,8,9,10,12,15,16,18,20,24,25,27,30,32,36] 

的第五十○萬之一是:

1962938367679548095642112423564462631020433036610484123229980468750 

印刷在第五十○萬酮(計算的短暫的時間後)的程序是:

merge [email protected](x:xs) [email protected](y:ys) = 
    case (x`compare`y) of 
    LT -> x:merge xs yys 
    EQ -> x:merge xs ys 
    GT -> y:merge xxs ys 

hamming = 1 : m 2 `merge` m 3 `merge` m 5 
    where 
    m k = map (k *) hamming 

main = print (hamming !! 499999) 

以非懶惰的語言以合理的速度計算該數字需要相當多的代碼和頭疼。有很多examples here