了解MonadIO法律

时间:2017-09-14 20:15:37

标签: haskell

来自source

module Control.Monad.IO.Class (
    MonadIO(..)
  ) where

-- | Monads in which 'IO' computations may be embedded.
-- Any monad built by applying a sequence of monad transformers to the
-- 'IO' monad will be an instance of this class.
--
-- Instances should satisfy the following laws, which state that 'liftIO'
-- is a transformer of monads:
--
-- * @'liftIO' . 'return' = 'return'@
--
-- * @'liftIO' (m >>= f) = 'liftIO' m >>= ('liftIO' . f)@

class (Monad m) => MonadIO m where
    -- | Lift a computation from the 'IO' monad.
    liftIO :: IO a -> m a

instance MonadIO IO where
    liftIO = id

是什么意思

liftIO (m >>= f) = liftIO m >>= (liftIO . f)

特别是(m >>= f)是什么意思?这里m是关于类型的函数,f是关于值的函数。所以这种符号不是无意义的吗?

1 个答案:

答案 0 :(得分:1)

正如评论中所述,法律中的m只是一个值变量,与m中使用的类型变量m不同class }定义。

如果您将法律改写为:

liftIO (act >>= f) = liftIO act >>= (liftIO . f)

相当于:

liftIO $ do x <- act     ===      do x <- liftIO act
            f x                      liftIO (f x)

了解到act是一个IO动作,然后可能会更清楚发生了什么。表达式act >>= f表示复合IO操作,在运行时,将运行IO操作act并将其返回值传递给f以生成新的IO操作(例如act2 })然后将运行。

法律规定,将此复合IO操作提升到另一个monad会创建一个操作,该操作在运行时等效运行act的提升版本,将其返回值传递给f以生成一个新的IO动作,将该动作提升到另一个monad,然后运行它。

作为一个具体示例,getLine >>= print是IO动作,它读取一行,然后在Haskell字符串语法中打印其值。法律规定你可以将其直接提升到另一个monad:

liftIO $ do x <- getLine
            print x

获取执行此操作的操作,或者您可以单独解除IO操作部件:

do x <- liftIO getLine
   liftIO (print x)

并获得完全相同的动作。