2012-01-26 21 views

Trả lời

36

Điều này là tốt; không có tràn ngăn xếp sẽ xảy ra. Stack tràn trong Haskell (và, thực sự, bất kỳ ngôn ngữ không nghiêm ngặt) là khác nhau với những người trong các ngôn ngữ khác; chúng phát sinh từ việc tích lũy các giá trị lớn mà không bao giờ đánh giá chúng, nhưng bạn không tích luỹ bất cứ thứ gì ở đây; chỉ cần sắp xếp chuỗi hành động vô hạn. Bạn có thể nghĩ về nó như thế này: Một khi dòng được in, hành động sẽ bị loại bỏ, và điều khiển đi thẳng vào main; không có gì được lưu trữ trên ngăn xếp vì không có gì phải được trả về. Đó là lý do tương tự bạn có thể lặp qua danh sách vô hạn mà không cần hết bộ nhớ: khi chương trình đi xa hơn trong danh sách, các ô danh sách trước đó được thu thập bởi bộ thu gom rác vì chúng không còn cần thiết nữa. Trong trường hợp này, các trình tự trước đó được khai hoang, vì không có lý do gì để giữ lại một hành động mà bạn đã thực hiện.

Điều đó nói rằng, một cách đẹp hơn để viết ví dụ cụ thể này là:

import Control.Monad 

main :: IO() 
main = forever $ putStrLn "do something" 

Tất nhiên, điều này sẽ không hoạt động nếu vòng lặp của bạn là bao giờ có ý định chấm dứt. forever được tự thực hiện với đệ quy, vì vậy không có lợi ích nào ngoài khả năng đọc để thực hiện việc này.

+0

lý do tại sao không có tràn ngăn xếp nào xảy ra nếu tôi làm như vậy? những gì của Haskell đệ quy khác nhau từ C của – snow

+0

Tôi đã mở rộng câu trả lời của tôi để hy vọng giải thích lý do tại sao một chút tốt hơn. – ehird

+0

tuyệt vời. cảm ơn rất nhiều! – snow

2

Điều bạn quan sát là kết quả của "loại bỏ cuộc gọi/tối ưu hóa cuộc gọi đuôi", điều này không có gì đặc biệt đối với Haskell. Xem ví dụ http://en.wikipedia.org/wiki/Tail_call

+3

Thực ra nó có một chút khác biệt trong Haskell, do sự lười biếng. Một số thứ không được tối ưu hóa bằng ngôn ngữ nghiêm ngặt * có thể được tối ưu hóa trong Haskell. Tuy nhiên, nếu bạn có một hàm Haskell nghiêm ngặt, thì TCO hoạt động gần giống như trong các ngôn ngữ nghiêm ngặt thực hiện tính năng này. –

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