Đây là một "giải thích" đề xuất của các IO
đơn nguyên. Nếu bạn muốn thực hiện "giải thích" này một cách nghiêm túc, thì bạn cần nghiêm túc thực hiện "RealWorld". Không liên quan dù action world
được đánh giá theo suy đoán hay không, action
không có bất kỳ tác dụng phụ nào, tác dụng của nó, nếu có, được xử lý bằng cách trả lại trạng thái mới của vũ trụ nơi các hiệu ứng đó đã xảy ra, ví dụ như một gói mạng đã được gửi. Tuy nhiên, kết quả của chức năng là ((),world)
và do đó trạng thái mới của vũ trụ là world
. Chúng ta không sử dụng vũ trụ mới mà chúng ta có thể đã đánh giá một cách suy đoán ở bên. Trạng thái của vũ trụ là world
.
Bạn có thể có một thời gian khó khăn mà nghiêm túc. Có nhiều cách tốt nhất là nghịch lý bề ngoài và vô nghĩa. Đồng thời đặc biệt là không rõ ràng hoặc điên rồ với quan điểm này.
"Đợi, đợi đã," bạn nói. " RealWorld
chỉ là một 'mã thông báo'. Nó không thực sự là trạng thái của toàn bộ vũ trụ." Được rồi, "giải thích" này không giải thích gì. Tuy nhiên, như một chi tiết triển khai , đây là cách mô hình GHC IO
. 1 Tuy nhiên, điều này có nghĩa là chúng ta có những "chức năng" kỳ diệu thực sự có tác dụng phụ và mô hình này không cung cấp hướng dẫn nào cho ý nghĩa của chúng. Và, vì các chức năng này thực sự có tác dụng phụ, mối quan tâm bạn nêu lên là hoàn toàn chính xác. GHC không cần phải đảm bảo RealWorld
và các chức năng đặc biệt này không được tối ưu hóa theo cách thay đổi hành vi dự định của chương trình.
Cá nhân (như có lẽ là hiển nhiên bây giờ), tôi nghĩ rằng mô hình "xuyên thế giới" IO
này chỉ là vô dụng và khó hiểu như một công cụ sư phạm. (Cho dù nó hữu ích cho việc triển khai, tôi không biết. Đối với GHC, tôi nghĩ nó giống như một cổ vật lịch sử.)
Một cách tiếp cận khác là xem IO
như một yêu cầu mô tả với các trình xử lý phản hồi. Có một số cách để làm điều này. Có lẽ dễ tiếp cận nhất là sử dụng một công trình đơn nguyên miễn phí, cụ thể là chúng ta có thể sử dụng:
data IO a = Return a | Request OSRequest (OSResponse -> IO a)
Có nhiều cách để làm cho điều này tinh vi hơn và có một số tính chất tốt hơn, nhưng đây đã là một cải tiến. Nó không đòi hỏi những giả định triết học sâu sắc về bản chất của thực tế để hiểu. Tất cả đều nói rằng đó IO
là một chương trình tầm thường Return
không làm gì ngoài việc trả về một giá trị, hoặc đó là một yêu cầu cho hệ điều hành với một trình xử lý cho phản hồi. OSRequest
có thể là một cái gì đó như:
data OSRequest = OpenFile FilePath | PutStr String | ...
Tương tự, OSResponse
có thể là một cái gì đó như:
data OSResponse = Errno Int | OpenSucceeded Handle | ...
(Một trong những cải tiến mà có thể được thực hiện là để làm cho mọi việc hơn gõ rất an toàn mà bạn biết bạn sẽ không nhận được OpenSucceeded
từ một PutStr
yêu cầu.) Mô hình này IO
là mô tả các yêu cầu mà có được giải thích bởi một số hệ thống (đối với "thực" IO
đơn nguyên này là thời gian chạy Haskell), và sau đó, có lẽ, hệ thống đó sẽ gọi trình xử lý mà chúng tôi đã cung cấp với một phản hồi. Tất nhiên, điều này cũng không đưa ra bất kỳ dấu hiệu nào về cách PutStr "hello world"
xử lý một yêu cầu như thế nào , nhưng nó cũng không giả vờ. Nó làm cho rõ ràng rằng điều này đang được ủy quyền cho một số hệ thống khác. Mô hình này cũng khá chính xác. Tất cả các chương trình người dùng trong các HĐH hiện đại cần phải yêu cầu HĐH thực hiện bất cứ điều gì.
Mô hình này cung cấp trực giác đúng. Ví dụ, nhiều người mới bắt đầu xem những thứ như <-
toán tử là "hủy ghép nối" IO
hoặc có quan điểm (không may được củng cố) rằng IO String
một "container" chứa "chứa" String
(và sau đó <-
lấy chúng ra). Quan điểm phản hồi yêu cầu này làm cho quan điểm này rõ ràng sai. Không có xử lý tập tin bên trong OpenFile "foo" (\r -> ...)
. Một điểm tương đồng phổ biến để nhấn mạnh điều này là không có bánh trong công thức làm bánh (hoặc có thể "hóa đơn" sẽ tốt hơn trong trường hợp này).
Mô hình này cũng hoạt động dễ dàng với đồng thời. Chúng ta có thể dễ dàng có một hàm tạo để OSRequest
thích Fork :: (OSResponse -> IO ()) -> OSRequest
và sau đó bộ thực thi có thể xen kẽ các yêu cầu được tạo bởi trình xử lý bổ sung này với trình xử lý bình thường theo cách nó thích. Với một số thông minh, bạn có thể sử dụng điều này (hoặc các kỹ thuật liên quan) để thực sự mô hình hóa những thứ như đồng thời trực tiếp hơn thay vì chỉ nói "chúng tôi đưa ra yêu cầu cho HĐH và mọi thứ xảy ra." Đây là cách IOSpec
thư viện hoạt động.
1 Hugs đã sử dụng một triển khai dựa trên tiếp tục IO
tương tự như những gì tôi mô tả mặc dù có chức năng mờ thay vì một loại dữ liệu rõ ràng. HBC cũng đã sử dụng triển khai dựa trên tiếp tục được xếp lớp trên IO dựa trên luồng phản hồi yêu cầu cũ. NHC (và do đó YHC) được sử dụng thunks, tức là xấp xỉ IO a = () -> a
mặc dù ()
được gọi World
, nhưng nó không phải là làm nhà nước đi qua. JHC và UHC sử dụng về cơ bản giống như GHC.