This FAQ的時間成本說哈斯克爾`seq`運營商
的序列運算符是
seq :: a -> b -> b
X
seq
Ÿ將評估X,足以確認這是不是底部,然後 丟棄結果並評估y。這可能看起來不太有用,但它 意味着保證x在考慮y之前被評估。
這是非常不錯的Haskell的,但它意味着,在
x `seq` f x
評估x
的成本將支付兩次(「廢棄結果」)?
This FAQ的時間成本說哈斯克爾`seq`運營商
的序列運算符是
seq :: a -> b -> b
X
seq
Ÿ將評估X,足以確認這是不是底部,然後 丟棄結果並評估y。這可能看起來不太有用,但它 意味着保證x在考慮y之前被評估。
這是非常不錯的Haskell的,但它意味着,在
x `seq` f x
評估x
的成本將支付兩次(「廢棄結果」)?
的seq
功能將丟棄的x
價值,但由於價值進行了評估,以x
所有引用「更新」不再指向未評估版本的x
,而是指向評估版本。因此,即使seq
評估並丟棄了x
,該值也已針對x
的其他用戶進行了評估,導致不會重複評估。
不,它不是計算和忘記,它是計算 - 它強制高速緩存。
例如,考慮下面的代碼:
let x = 1 + 1
in x + 1
由於Haskell是惰性的,這種評估爲((1 + 1) + 1)
。一個thunk,包含一個thunk和一個的總和,內部thunk是一個加一。
讓我們使用JavaScript,非懶語,以示這是什麼樣子:
function(){
var x = function(){ return 1 + 1 };
return x() + 1;
}
的thunk seq
串聯起來這樣才能cause stack overflows, if done repeatedly,使救援。
let x = 1 + 1
in x `seq` (x + 1)
我在說謊時,我告訴你,這個計算結果爲(2 + 1)
,但這是幾乎真的 - 它只是2的計算被強制休息發生(但仍是計算2之前發生懶洋洋)。
去回的javascript:
function(){
var x = function(){ return 1 + 1 };
return (function(x){
return x + 1;
})(x());
}
我相信x
只會被評估一次(並且結果保留供將來使用,這是惰性操作的典型特徵)。這種行爲使得seq
有用。
當然seq
by itself does not "evaluate" anything。它只記錄強制順序依賴關係。強制本身由模式匹配觸發。當seq x (f x)
被強制時,x
將被強制首先(記憶結果值),然後f x
將被強制。Haskell的懶惰評估意味着它記錄表達式的強迫結果,因此不會重複「評估」(這裏是可怕的引號)。
我把「評價」納入可怕的報價中,因爲它暗示完整評價。用Haskell wikibook,
, 的話說:「Haskell值是高度分層的;'評估'Haskell值可能意味着評估這些層中的任何一個。」
讓我重申:seq
本身不計算任何東西。seq x x
在任何情況下均不評估x
。 seq x (f x)
在f = id
與the report似乎一直在說的相反時不會評估任何內容。
您可以隨時與unsafePerformIO
或trace
檢查...
import System.IO.Unsafe (unsafePerformIO)
main = print (x `seq` f (x + x))
where
f = (+4)
x = unsafePerformIO $ print "Batman!" >> return 3
也許 「丟棄的結果」 是太強大了。它以同樣的方式丟棄結果,const拋棄它的第二個參數。如果論證已經被評估,它不會以某種方式評估它或丟棄結果,它只是忽略它。 「x'seq'y將評估x,足以檢查它不是底部的,然後_ignore_結果並評估y」可能是更好的方式來描述它。 – MatrixFrog 2012-03-15 07:32:33
對我來說,Haskell的計算模型與我的核心編程語言(C++)有很大不同。 – 2012-03-15 09:48:50