Haskell 返回IO操作的后果是什么?
在Haskell中,类型构造函数Haskell 返回IO操作的后果是什么?,haskell,io,monads,io-monad,Haskell,Io,Monads,Io Monad,在Haskell中,类型构造函数IO是一个monad,它配备了return语句,可以将任何表达式提升到其IO版本 并没有什么能阻止我们将已经是IO操作的内容提升到它的IO版本-给我们一种形式IO(ioa) 例如,我可以编写以下程序: main = return . print $ "Hello world" 一经执行,什么也不做 我的问题是,当执行此主程序时,引擎盖下会发生什么 在任何情况下,返回IO操作是否有意义?IO通常近似于状态现实世界,即在“真实世界”上运行的状态单子returnfor
IO
是一个monad,它配备了return
语句,可以将任何表达式提升到其IO
版本
并没有什么能阻止我们将已经是IO
操作的内容提升到它的IO
版本-给我们一种形式IO(ioa)
例如,我可以编写以下程序:
main = return . print $ "Hello world"
一经执行,什么也不做
我的问题是,当执行此主程序时,引擎盖下会发生什么
在任何情况下,返回IO操作是否有意义?
IO
通常近似于状态现实世界,即在“真实世界”上运行的状态
单子return
forState
生成一个不会改变包含状态的操作。因此,打个比方,返回
将任何内容发送到IO
也不会做任何事情。不仅当您返回
某些IO a
时,而且当您返回任何a
时
返回一个IO
操作可用于在一个地方建立一个计算(沿途将一些值捕获到一个闭包中)并在其他地方执行它。很像在C中传递回调
实际上,要建立一个IO
计算并将其传递到其他地方,您可以在do块内使用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
..
在这里,我们需要一个filename
来创建我们的操作,但是getLine
也在IO
中。这就是额外级别的IO
出现的地方。当然,这个示例是合成的,因为您可以在引擎盖下执行filename,运行时会有效地丢弃IO
actionmain
的结果,这就是为什么它通常被定义为IO()
。这意味着如果main
实际上有一个类似IO(IO Int)
的类型,那么就没有真正的问题。执行IO
操作,结果(另一个IO
操作)被丢弃,未执行
在程序的更深处,更可能触发类型错误。例如,fmap doSomething(return.getLine)
不会进行类型检查,如果您的意思是fmap doSomething getLine
小挑剔:这是一个IO(IO a)
@Zeta谢谢!现在修正了,你能不能加一个你在最后一段中谈到的例子?@jsevilamol更新了我的答案。
main :: IO ()
main = do
act <- do
filename <- getLine
return (readFile filename)
foo act