簡體   English   中英

需要幫助來理解Haskell的惰性評估行為

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM