Tiêu đề gây nhầm lẫn cho một câu hỏi khó hiểu! Tôi hiểu a) monads, b) đơn nguyên IO, c) đơn vị Cont (Control.Monad.Cont) và d) đơn biến áp tiếp tục ContT. (Và tôi mơ hồ hiểu các biến thế đơn nguyên nói chung - mặc dù không đủ để trả lời câu hỏi này.) Tôi hiểu cách viết một chương trình ở đó tất cả các chức năng đang ở chế độ Đơn nguyên (Cont r a
) và tôi hiểu cách viết chương trình trong đó tất cả các chức năng nằm trong đơn vị Cont/IO kết hợp (ContT r IO a
).Thoát khỏi đơn nguyên IO bên trong đơn vị Continuation
Nhưng tôi đang tự hỏi làm thế nào tôi có thể viết một chương trình mà một số chức năng đang ở trong một Tiếp/IO đơn nguyên kết hợp (ContT r IO a
) và chức năng khác chỉ trong đơn nguyên Tiếp (Cont r a
). Về cơ bản, tôi muốn viết toàn bộ chương trình theo kiểu tiếp tục, nhưng chỉ sử dụng đơn nguyên IO khi cần thiết (giống như trong mã Haskell "thông thường", tôi chỉ sử dụng đơn nguyên IO khi cần thiết).
Ví dụ xem xét hai chức năng này, trong phong cách không tiếp tục:
foo :: Int -> IO Int
foo n = do
let x = n + 1
print x
return $ bar x
bar :: Int -> Int
bar m = m * 2
Lưu ý rằng foo
đòi hỏi IO nhưng bar
là tinh khiết. Bây giờ tôi đã tìm ra cách viết mã này sử dụng đầy đủ các đơn nguyên tiếp tục, nhưng tôi cần phải sợi IO qua bar
cũng như:
foo :: Int -> ContT r IO Int
foo n = do
let x = n + 1
liftIO $ print x
bar x
bar :: Int -> ContT r IO Int
bar m = return $ m * 2
tôi làm muốn tất cả các mã của tôi trong phong cách tiếp tục, nhưng tôi don' t muốn sử dụng trình đơn IO trên các chức năng không yêu cầu. Về cơ bản, tôi muốn để xác định bar
như thế này:
bar :: Int -> Cont r Int
bar m = return $ m * 2
Thật không may, tôi không thể tìm thấy một cách để gọi một hàm Cont r a
đơn nguyên (bar
) từ bên trong một hàm ContT r IO a
đơn nguyên (foo
). Có cách nào để "nâng" một đơn nguyên không biến đổi thành một biến đổi không? tức là, làm cách nào tôi có thể thay đổi dòng "bar x
" trong foo
để nó có thể gọi chính xác bar :: Int -> Cont r Int
?
Cảm ơn. Điều đó hoạt động. Tôi cũng tìm thấy giải pháp của riêng mình, mà đã cho tôi chính xác những gì tôi muốn (tôi không phải thay đổi 'Bar'):' liftCont :: Cont (m r) a -> ContT r m a'; 'liftCont c = ContT $ runCont c'. Giải pháp của tôi giải nén 'Cont' và xây dựng một' ContT'. Tôi nghĩ rằng giải pháp của bạn đẹp hơn vì nó đa hình và không yêu cầu thao tác thực sự của cấu trúc dữ liệu, vì vậy hãy đánh dấu vào bạn. Nhưng tôi sẽ đăng bài của tôi như một câu trả lời khác, vì nó hữu ích trong trường hợp bạn không thể sửa đổi 'bar'. Ngoài ra 1 để giải thích lý do tại sao nó sẽ không thể sử dụng IO trong 'bar'. – mgiuca