2015-02-12 24 views
7

Tìm hiểu Bạn một Haskell nói về foldl' thay thế cho foldl vì dễ bị tràn ngăn xếp.Câu hỏi về nếp gấp và ngăn xếp ngăn xếp

  • Theo LYAH, foldl (+) 0 (replicate 1000000 1) nên ngăn xếp tràn, nhưng không có trên máy của tôi. Tại sao không? Thậm chí nếu tôi tăng số đó lên 10 triệu, nó không bị tràn. Nó chỉ mất rất nhiều bộ nhớ cho đến khi máy tính OS X của tôi trở nên không sử dụng được và tôi phải khởi động lại nó.
  • Trong trường hợp nào tôi nên sử dụng foldl thay vì foldl'? Trong kinh nghiệm của tôi foldl' "chỉ hoạt động" trong khi foldl về cơ bản có thể sụp đổ máy tính của tôi (xem ở trên).
  • Tôi không hiểu tại sao không có gì tương tự cho foldr. Tại sao không thể foldr tràn ngăn xếp và tại sao không có foldr'?
+0

bản sao có thể có của [Chọn trái và phải trong danh sách vô hạn] (http://stackoverflow.com/questions/7396978/left-and-right-folding-over-an-infinite-list) –

+0

Câu trả lời cho câu hỏi thứ hai của bạn và các câu hỏi thứ ba đang chờ bạn tại https://www.haskell.org/haskellwiki/Foldr_Foldl_Foldl ' – Jubobs

+0

Điểm chính xác mà tại đó máy tính của bạn sẽ đạt đến một stackoverflow hoặc hết bộ nhớ phụ thuộc vào hệ điều hành của bạn, những chương trình khác mà bạn chạy và phần cứng vật lý của bạn. Một quả mâm xôi pi sẽ hết RAM sớm hơn máy tính đồ họa (có thể có> 100GB RAM). Hệ điều hành của bạn cũng có thể sử dụng trao đổi theo một cách cụ thể để quản lý các chương trình yêu cầu nhiều bộ nhớ hơn. – bheklilr

Trả lời

12

Nó không sụp đổ với ngăn xếp ngăn xếp vì ngăn xếp hiện được vô hạn theo mặc định. Nghĩa là, hành vi thời gian chạy GHC mặc định là cho phép ngăn xếp phát triển vô thời hạn - không có ràng buộc nào có thể kích hoạt lỗi tràn ngăn xếp.

https://ghc.haskell.org/trac/ghc/ticket/8189

Dưới đây là một mô tả cách hoạt động:

ngăn xếp Chủ đề (bao gồm cả ngăn xếp các chủ đề chính của) sống trên heap. Khi ngăn xếp phát triển, các khối ngăn xếp mới được thêm theo yêu cầu; nếu ngăn xếp co lại, các khối ngăn xếp bổ sung này được thu thập bởi bộ thu gom rác . Kích thước ngăn xếp ban đầu mặc định là nhỏ, theo thứ tự để giữ cho thời gian và chi phí không gian cho việc tạo luồng tới mức tối thiểu là và làm cho nó trở nên thực tế để tạo ra các luồng cho các tác phẩm nhỏ bé .

+1

Bạn có thể muốn đưa ra câu trả lời của mình một chút, nhưng +1 dù sao đi nữa. – Jubobs

4

Tại sao không thể gập xếp chồng lên nhau và tại sao không có nếp gấp '?

Vâng, foldr không phải là đệ quy đuôi, tức là nó không gọi trực tiếp vào bản thân:

foldr f a (x:xs) = f x (foldr f a xs) 

Sau foldr giảm, điều khiển đi đến người dùng cung cấp f. Do đó, không cần phải có một số foldr' để buộc các đối số trước khi chuyển chúng đến f: nếu điều đó được mong muốn, người gọi chỉ có thể vượt qua một số f nghiêm ngặt (ví dụ: khai thác các mẫu kiểu bang hoặc seq).

Cho dù nó tràn ngăn xếp phụ thuộc vào những gì f thực hiện. Ví dụ:

f x y = x 

sẽ khiến danh sách chỉ được truy cập trong phần tử đầu tiên. Ngược lại,

f x y = seq y x 

có thể gây tràn bộ nhớ (hoặc hành vi sử dụng bộ nhớ).Thay vào đó,

f x y = x+1 : y 

sẽ khiến danh sách đầu ra được tạo ra một cách lười biếng, tương tự như map (+1) xs, mà không có bất ngờ khó chịu.

Khi @dfeuer chỉ ra, có tồn tại Data.Foldable.foldr' hoạt động trên bất kỳ Foldable nào dưới dạng vòng lặp đúng nghiêm ngặt. Trên danh sách, đó là khá nhiều dự phòng, như đã thảo luận ở trên. Trên các loại Foldable khác, thay vào đó nó có thể có ý nghĩa.

+2

Nó có thể là giá trị chỉ ra rằng có * là * một 'foldr''. Nó chỉ trong 'Data.Foldable' thay vì' Data.List', bởi vì nó hoàn toàn vô dụng đối với các danh sách. – dfeuer

+0

Đặt một cách khác, lý do tại sao 'foldr'' gần như vô dụng trong danh sách là chúng được liên kết đơn lẻ ngay từ đầu, và bạn phải recurse đến cuối chỉ để tìm yếu tố để bắt đầu gấp. Vì vậy, đối với một danh sách dài bạn kết thúc bằng cách sử dụng rất nhiều stack hoặc heap dù sao đi nữa. –

Các vấn đề liên quan