2011-06-03 119 views
11

我開始Haskell,正在看一些數據類型用「!」定義的庫。從字節串庫的例子:嚴格聲明的要點是什麼?

data ByteString = PS {-# UNPACK #-} !(ForeignPtr Word8) -- payload 
        {-# UNPACK #-} !Int    -- offset 
        {-# UNPACK #-} !Int    -- length 

現在我看到this question作爲這意味着什麼解釋,我想這是很容易理解的。但我現在的問題是:使用這個的意義何在?既然表達式會在需要時進行評估,爲什麼要強制早期評估呢?

在對這個問題的第二個答案C.V.漢森說:「有時懶惰的開銷可能太多或浪費了」。這是否意味着它用於節省內存(保存該值比保存表達式更便宜)?

一個解釋和一個例子會很棒!

謝謝!

[編輯]我想我應該選擇一個沒有{ - #UNPACK# - }的例子。所以讓我自己做一個。這會有道理嗎?是的,爲什麼和在什麼情況下?

data MyType = Const1 !Int 
      | Const2 !Double 
      | Const3 !SomeOtherDataTypeMaybeMoreComplex 
+0

懶惰可以對代碼產生很大的影響,主要的原因是當嚴格程序需要恆定的空間時,懶惰程序通常在線性空間中運行。但在你的例子中,真正的原因可能與外部函數操縱的數據有關,這些外部函數不知道如何強制懶惰評估。 – 2011-06-03 19:45:24

+0

沒有。ForeignPtr可以傳遞給外部函數,當然,但不是結構本身 - 即使是嚴格/解壓縮註釋,沒有爲本地haskell結構定義ABI – bdonlan 2011-06-03 19:51:00

回答

13

這裏的目標並不是嚴格的把這些元素包裝到數據結構中。沒有嚴格的規定,這三個構造函數參數中的任何一個都可以指向堆分配值結構或堆分配延遲評估thunk。嚴格來說,它只能指向堆分配的價值結構。通過嚴格性和打包結構,可以將這些值串聯起來。

由於這三個值中的每一個都是一個指針大小的實體,並且無論如何都嚴格地被訪問,所以當使用這種結構時,強制嚴格和壓縮結構保存指針間接。

在更一般的情況下,嚴格標註可以幫助減少空間泄漏。考慮這樣的情況:

data Foo = Foo Int 

makeFoo :: ReallyBigDataStructure -> Foo 
makeFoo x = Foo (computeSomething x) 

沒有嚴格的註釋,如果你只是叫makeFoo,將建立一個Foo指向指向ReallyBigDataStructure一個thunk,在內存中保存,直到東西迫使thunk的評估。如果我們不是有

data Foo = Foo !Int 

這迫使computeSomething評價立即着手(當然,只要東西力量makeFoo本身),從而避免留給ReallyBigDataStructure參考。

請注意,這是與字節串代碼不同的用例;字節串代碼相當頻繁地強制它的參數,所以它不太可能導致空間泄漏。最好將字節串代碼解釋爲純粹的優化,以避免指針取消引用。

+0

也許我應該選擇一個沒有打包/解包的例子(我不明白/還沒有看過)。無論如何,「指針大小」實體的含義是什麼?我想我對這些指針有點困惑,因爲根據我的理解,Haskell並沒有真正的指針。這是一些較低級別的編譯器相關的東西(這不是haskell本身的一部分)? – o1iver 2011-06-03 20:09:55

+0

是的,這是結構的實際內存表示的低級優化。 – bdonlan 2011-06-03 20:10:38

+0

好吧,這是有道理的。不過,我編輯了我的答案,並添加了另一個例子(^^)。在這種情況下,相同的答案是否有效? – o1iver 2011-06-03 20:20:48