Đây là một trong những điều nhỏ nhặt phức tạp khiến tôi bối rối khi lần đầu tiên tôi thử Haskell. Bạn hiểu nhầm ý nghĩa của cấu trúc <-
trong ký hiệu. result <- f handle
không có nghĩa là "chỉ định giá trị của f handle
đến result
"; nó có nghĩa là "liên kết result
với giá trị 'được trích xuất' từ giá trị monome của f handle
" (trong đó 'trích xuất' xảy ra theo cách nào đó được xác định bằng cá thể Monad cụ thể mà bạn đang sử dụng, trong trường hợp này là đơn nguyên IO).
Tức là, đối với một số đơn nguyên typeclass m, báo cáo kết quả <-
mất một biểu hiện của loại m a
ở phía bên tay phải và một biến kiểu a
ở phía bên tay trái, và liên kết với các biến đến một giá trị. Do đó, trong ví dụ cụ thể của bạn, với result <- f handle
, chúng tôi có các loại f result :: IO a
, result :: a
và return result :: IO a
.
Ghi chú PS cũng có dạng đặc biệt là let
(không có từ khóa in
trong trường hợp này!) Hoạt động như một đối tác thuần túy đối với <-
. Vì vậy, bạn có thể viết lại ví dụ của bạn như:
withFile' :: FilePath -> IOMode -> (Handle -> IO a) -> IO a
withFile' path mode f = do
handle <- openFile path mode
let result = f handle
hClose handle
result
Trong trường hợp này, bởi vì let
là một nhiệm vụ đơn giản, loại result
là IO a
.
Nguồn
2011-12-19 23:18:50
Oh d'oh! Hoàn toàn bỏ lỡ toán tử _sucking_ '<-'! – drozzy
Có thể nó cũng là 'let result = f handle; hClose xử lý; result' hoặc tôi đã không đọc lại một lần nữa? – delnan
@delnan sẽ là đường dẫn chế độ 'do {handle <- openFile; hClose xử lý; f xử lý; } ', do đó,' f handle' có lẽ sẽ phàn nàn về một chốt đóng. –