liftIO 的目的是什么?

zer*_*ing 9 haskell

我有以下来自互联网的代码片段:

calculateLength :: LengthMonad Int
calculateLength = do
  -- all the IO operations have to be lifted to the IO monad in the monad stack
  liftIO $ putStrLn "Please enter a non-empty string: "
  s <- liftIO getLine
  if null s
    then throwError "The string was empty!"
    else return $ length s
Run Code Online (Sandbox Code Playgroud)

并不能理解,为什么作者使用liftIO

的目的是liftIO什么?

它的定义如下:

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

可以举IO a -> [a]吗?它看起来像自然的转变。

chi*_*chi 8

IO像操作一样getLine, putStrLn "..."只能在IOmonad内部工作。在任何其他 monad 中使用它们将触发类型错误。

尽管如此,仍有许多 monadsM是根据IO(例如StateT Int IO,显然你的LengthMonad)定义的,因此它们允许将IO动作转换为M-actions,并以这样的方式执行。

但是,我们需要对每个进行转换M

convertIOintoM1 :: IO a -> M1 a 
convertIOintoM2 :: IO a -> M2 a
convertIOintoM3 :: IO a -> M3 a
...
Run Code Online (Sandbox Code Playgroud)

由于这很麻烦,库定义了一个MonadIO具有这种转换功能的类型类,这样上面的所有函数都可以被命名liftIO

在实践中,liftIO每次想要IO在另一个 monad 中运行操作时都会使用它,前提是此类 monad 允许。