Riffing on answer của sepp2k, đây là một ví dụ tuyệt vời để hiển thị sự khác biệt giữa Functor
và Monad
.
Các Haskell độ nét tiêu chuẩn của Monad
đi một cái gì đó như thế này (giản thể):
class Monad m where
return :: a -> m a
(>>=) :: m a -> (a -> m b) -> m b
Tuy nhiên, đây không phải là cách duy nhất các lớp có thể đã được xác định. Một thay thế chạy như thế này:
class Functor m => Monad m where
return :: a -> m a
join :: m (m a) -> m a
Cho rằng, bạn có thể xác định >>=
về fmap
và join
:
(>>=) :: Monad m => m a -> (a -> m b) -> m b
ma >>= f = join (f <$> ma)
Chúng tôi sẽ xem xét điều này trong một phác thảo đơn giản của vấn đề bạn chay vao. Những gì bạn đang làm có thể được biểu đồ hóa như thế này:
ma :: IO a
f :: a -> IO b
f <$> ma :: IO (IO b)
Bây giờ bạn đã bị mắc kẹt bởi vì bạn cần một IO b
, và lớp Functor
không có hoạt động đó sẽ giúp bạn có từ IO (IO b)
. Cách duy nhất để có được nơi bạn muốn là để nhúng vào Monad
, và các hoạt động join
chính xác là những gì giải quyết nó:
join (f <$> ma) :: IO b
Nhưng theo định nghĩa join
/<$>
của >>=
, đây là giống như:
ma >>= f :: IO a
Lưu ý rằng thư viện Control.Monad
đi kèm với phiên bản join
(được viết bằng return
và (>>=)
); bạn có thể đặt nó vào chức năng của bạn để có được kết quả mong muốn. Nhưng điều tốt hơn để làm là nhận ra rằng những gì bạn đang cố gắng làm là đơn giản về cơ bản, và do đó <$>
không phải là công cụ thích hợp cho công việc. Bạn đang cho ăn kết quả của một hành động khác; mà về bản chất yêu cầu bạn sử dụng Monad
.
Nguồn
2013-05-25 17:56:39
cảm giác trực giác của mình, nó giúp: 'removeFile' thêm 1 hiệu ứng.nếu chúng ta chỉ muốn 1 hiệu ứng cuối cùng, chúng ta phải cho ăn nếu có thứ gì đó có hiệu lực 0. 'lst' đã có hiệu lực rồi. vì vậy chúng ta cần loại bỏ nó trước tiên, bằng cách sử dụng liên kết (giai đoạn tính toán) chạy hiệu ứng để lấy giá trị với hiệu ứng 0 – nicolas