Nó chỉ ra rằng bạn có thể giải quyết vấn đề compress
của bạn bằng cách sử dụng một foldr
với chức năng ba đối số.
compress :: Eq a => [a] -> [a]
compress [] = []
compress (z:zs) = z : foldr f (const []) zs z
where f x k w | x==w = k x
| otherwise = x : k x
Hãy phân tích điều đó. Trước tiên, chúng tôi có thể cải thiện khả năng đọc bằng cách thay đổi hai dòng cuối cùng thành
where f x k = \w -> if x==w then k x else x : k x
Điều này cho thấy chức năng nhị phân không có gì ngoài chức năng nhị phân trả về hàm đơn nhất. Lợi thế của việc xem xét nó theo cách này là foldr
được hiểu rõ nhất khi truyền một hàm nhị phân. Thật vậy, chúng tôi là chuyển một hàm nhị phân, chức năng này chỉ xảy ra để trả về một hàm.
Hãy tập trung vào các loại bây giờ:
f :: a -> (a -> [a]) -> (a -> [a])
f x k
Vì vậy, x::a
là yếu tố của danh sách chúng tôi đang gấp trên. Chức năng k
là kết quả của nếp gấp trên đuôi danh sách. Kết quả của f x k
là thứ có cùng loại với k
.
\w -> if .... :: (a -> [a])
Ý tưởng tổng thể đằng sau hàm ẩn danh này như sau. Tham số k
đóng vai trò giống như acc
trong mã OP, ngoại trừ nó là hàm mong đợi trước đó phần tử w
trong danh sách trước khi tạo danh sách được nén tích lũy.
Cụ thể, chúng tôi sử dụng k x
khi chúng tôi sử dụng acc
, chuyển phần tử hiện tại sang bước tiếp theo, kể từ thời điểm đó x
sẽ trở thành phần tử trước w
. Ở cấp cao nhất, chúng tôi vượt qua z
đến chức năng được trả về bởi foldr f (const [])
.
Biến thể compress
này lười, không giống như giải pháp được đăng.Trong thực tế, giải pháp đã đăng cần phải quét toàn bộ danh sách trước khi bắt đầu sản xuất một cái gì đó: điều này là do (\x acc -> ...)
bị nghiêm ngặt trong acc
và việc sử dụng last xs
. Thay vào đó, đầu ra nén ở trên liệt kê các phần tử theo kiểu "truyền trực tuyến". Thật vậy, nó hoạt động với danh sách vô hạn cũng như:
> take 10 $ compress [1..]
[1,2,3,4,5,6,7,8,9,10]
Điều đó đang được nói, tôi nghĩ rằng sử dụng một foldr
đây cảm thấy một chút lạ: các mã trên được cho là ít có thể đọc hơn so với đệ quy rõ ràng
Bạn có thể thụ thai. trong nhiều trường hợp foldr mất hơn 2 đối số, ví dụ: 'foldr (\ fgx -> f (gx)) (\ x -> x)'. – user2407038
Tôi không chắc mình sẽ sử dụng 'fold r' để thực hiện chức năng 'compress' của bạn. Điều gì sẽ xảy ra nếu đối số là danh sách trống? – Jubobs
Việc triển khai '' foldr'' sẽ tốt, bạn chỉ cần có một mẫu đầu tiên có thể xử lý trường hợp của một danh sách trống '' compress '[] = [] '' –