首页 文章

返回IO操作会产生什么后果?

提问于
浏览
3

在Haskell中,类型构造函数 IO 是一个配有 return 语句的monad,它将任何表达式提升到 IO 版本 .

没有什么能阻止我们将已经 IO 的动作解除为 IO 版本 - 给我们一种形式 IO (IO a) .

所以我可以编写以下程序:

main = return . print $ "Hello world"

执行时什么都没做 .

我的问题是,执行此主程序时会发生什么?

有没有什么情况可以让 return 进行IO动作?

2 回答

  • 3

    IO 通常近似于 State RealWorld ,即 State monad,它在"real world"上运行 . return for State 生成一个不会改变包含状态的动作 . 因此,通过类比, returnIO 的任何内容都没有做任何事情 . 不仅当你 return 某些 IO a ,而且 a .

    返回 IO 动作可用于在一个地方构建计算(沿途捕获一些值到闭包中)并在其他地方执行 . 就像在C中传递回调一样

    实际上,要构建 IO 计算并将其传递到其他地方,您可以在do-block中使用 let

    main :: IO ()
    main = do
      let act = readFile "somefile" -- action is not performed yet
      foo act -- pass the action as a parameter
    
    foo :: IO () -> IO ()
    foo act = do
      .. do something
      result <- act -- actually perform the action
      ..
    

    在这种情况下,您不需要 return IO a 值 .

    但是,如果构建计算本身的过程需要您执行 IO 动作,那么's where you'd需要这样的事情 . 在我们的示例中,让我们要求用户打开文件名:

    main :: IO ()
    main = do
      act <- do
        filename <- getLine
        return (readFile filename)
      foo act
    

    在这里,我们需要一个 filename 来创建我们的动作,但 getLine 也在 IO 中 . 这就是 IO 的额外水平 . 当然,这个例子是合成的,因为你可以在 main 中执行 filename <- getLine .

  • 2

    在引擎盖下,运行时有效地丢弃了 IO action main 的结果,这就是为什么它通常被定义为 IO () . 这意味着如果 main 实际上具有类似 IO (IO Int) 的类型,则没有实际问题 . 执行 IO 操作,结果(另一个 IO 操作)被丢弃,未执行 .

    在程序中,您更有可能触发类型错误 . 例如, fmap doSomething (return . getLine) 将不会进行类型检查,如果您的意思是 fmap doSomething getLine .

相关问题