Tôi đã chơi đùa với các định nghĩa để hiểu rõ hơn mô hình đánh giá và viết hai cho chiều dài của một danh sách.Tại sao chức năng độ dài nghiêm ngặt lại hoạt động nhanh hơn đáng kể?
Định nghĩa ngây thơ:
len :: [a] -> Int
len [] = 0
len (_:xs) = 1 + len xs
Các nghiêm ngặt (và đuôi-đệ quy) định nghĩa:
slen :: [a] -> Int -> Int
slen [] n = n
slen (_:xs) !n = slen xs (n+1)
len [1..10000000]
mất khoảng 5-6 giây để thực hiện.
slen [1..10000000] 0
mất khoảng 3-4 giây để thực hiện.
Tôi tò mò tại sao. Trước khi tôi kiểm tra các buổi biểu diễn, tôi đã tích cực rằng họ sẽ biểu diễn như nhau bởi vì len
chỉ nên có thêm một bài đánh giá để đánh giá nhiều nhất. Đối với mục đích trình diễn:
len [a,b,c,d]
= 1 + len [b,c,d]
= 1 + 1 + len [c,d]
= 1 + 1 + 1 + len [d]
= 1 + 1 + 1 + 1 + len []
= 1 + 1 + 1 + 1 + 0
= 4
Và
slen [a,b,c,d] 0
= slen [b,c,d] 1
= slen [c,d] 2
= slen [d] 3
= slen [] 4
= 4
Điều gì làm cho slen
nhanh hơn trông thấy?
P.S. Tôi cũng đã viết một hàm lười đệ quy đuôi (giống như slen
nhưng lười) như là một nỗ lực để đóng-vào lý do - có lẽ đó là vì nó là đệ quy đuôi - nhưng nó thực hiện giống như định nghĩa ngây thơ.
Bước cuối cùng của 'len' không phải là O (1). Nó là O (n) để cộng các số n lại với nhau. 'slen' cũng sử dụng bộ nhớ O (n) trong khi' len' sử dụng bộ nhớ O (1). –
@DavidYoung Ồ, tôi hiểu rồi! Bạn được chào đón để viết nó như là một câu trả lời. Bạn cũng có thể giải thích mức tiêu thụ bộ nhớ? (hoặc chỉ tham chiếu đến nơi tôi có thể hiểu thêm). Cảm ơn rất nhiều! – MasterMastic
Xin lỗi, tôi đã quay lại. 'len' sử dụng bộ nhớ O (n) và' slen' sử dụng bộ nhớ O (1). –