[英]Need help in understanding the lazy evaluation behavior of Haskell
我寫了兩個版本的nqueens問題,我認為它們應該具有相似的效率,但事實並非如此。 我認為這是由於Haskell的懶惰評估行為。 有人可以解釋它如何適用於以下示例,
nqueens1 n 1 = [[i] | i <- [1..n]]
nqueens1 n k = [ i:q | i <- [1..n], q <- (nqueens1 n (k - 1)), isSafe i q k]
isSafe i q n = isSafeHelper i (zip q [(n-1),(n-2)..1])
where isSafeHelper i [] = True
isSafeHelper i (x:xs) = (i /= fst x) && abs(i - (fst x)) /= abs(n - (snd x)) &&
isSafeHelper i xs
nqueens2 n 1 = [[i] | i <- [1..n]]
nqueens2 n k = [ i:q | i <- [1..n], q <- boards, isSafe i q k]
where boards = nqueens2 n (k-1)
您可以通過調用nqueens1 8 8或nqueens2 8 8來評估它們,以評估它的大小為8的電路板。
雖然nqueens2非常有效,但nqueens1存在性能問題。 我相信這是因為遞歸調用(nqueens n(k-1))被多次評估。 根據我對Haskells懶惰評估的理解,情況應該不是這樣。
請幫助我理解這種行為。
提前致謝。
是的,遞歸調用被多次評估。 具體而言,針對i
每個值評估一次。
如果你想避免這種情況,你可以重新排列生成器,使q <-
部分出現在i <-
部分之前:
[ i:q | q <- nqueens2 n (k - 1), i <- [1..n], isSafe i q k]
但是,這將改變結果的順序。 如果這是不可接受的,你可以使用let
來計算一次遞歸調用的結果,然后像這樣使用它:
[ i:q | let rec = nqueens2 n (k - 1), i <- [1..n], q <- rec, isSafe i q k]
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.