Tôi đã viết hai phiên bản của vấn đề nqueens và tôi nghĩ rằng họ nên có hiệu quả tương tự nhưng nó không phải như vậy. Tôi nghĩ rằng đó là do hành vi đánh giá lười biếng của Haskell. Có thể ai đó xin vui lòng giải thích cách hoạt động cho các ví dụ sau,Cần giúp đỡ trong việc hiểu hành vi đánh giá lười biếng của 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)
Bạn có thể đánh giá chúng bằng cách gọi nqueens1 8 8 hoặc nqueens2 8 8 để đánh giá nó cho một hội đồng quản trị kích thước 8.
Trong khi nqueens2 hoạt động khá hiệu quả nqueens1 có vấn đề hiệu suất. Tôi tin rằng đó là bởi vì các cuộc gọi đệ quy (nqueens n (k-1)) đang được đánh giá nhiều lần. Từ sự hiểu biết của tôi về đánh giá lười biếng Haskells này không phải là trường hợp.
Hãy giúp tôi hiểu rõ hành vi này.
Xin cảm ơn trước.
"đánh giá Lazy" là về đánh giá điều muộn - không phải về tránh đánh giá một cái gì đó nhiều lần. –
@DanielWagner Trên thực tế sự khác biệt giữa đánh giá lười biếng và gọi theo tên là chính xác rằng các biểu thức nhất định sẽ được đánh giá nhiều lần bằng cách sử dụng gọi theo tên chỉ được đánh giá một lần bằng cách sử dụng đánh giá lười biếng. Đó là không liên quan đến vấn đề ở đây mặc dù. – sepp2k
@ sepp2k Bạn nói đúng, tôi nên nói chính xác hơn, hoặc bằng cách nói "gọi theo tên" thay vì "đánh giá lười biếng" hoặc bằng cách nói "ghi nhớ" thay vì "tránh đánh giá điều gì đó nhiều lần". –