IO = monad的定义是什么?

在看到List和Maybe monads是如何定义的之后,我自然而然地开始对IO monad的操作>>=return是如何定义的。

IO没有具体的实现; 这是一个抽象types,Haskell报告没有定义确切的实现。 事实上,没有什么能够停止实现IOMonad实例作为编译器原语的实现,根本没有Haskell的实现。

基本上, Monad被用作IO接口 ,它本身不能在纯粹的Haskell中实现。 这可能是你在这个阶段需要知道的所有东西,并且潜在的实现细节可能只是混淆,而不是提供洞察力。

这就是说,如果你看GHC的源代码,你会发现它代表IO a一个函数,看起来像State# RealWorld -> (# State# RealWorld, a #) (使用一个未装箱的元组作为返回types),但这是误导性的; 这是一个实现细节,而这些State# RealWorld值实际上并不存在于运行时。 IO在理论上或实践上不是一个国家的单子。

相反,GHC使用不纯的原语来实现这些IO操作; State# RealWorld “values”只是通过从一个语句引入数据依赖关系来停止编译器重新sorting语句。

但是如果你真的想看GHC的return(>>=) ,这里是:

 returnIO :: a -> IO a returnIO x = IO $ \ s -> (# s, x #) bindIO :: IO a -> (a -> IO b) -> IO b bindIO (IO m) k = IO $ \ s -> case ms of (# new_s, a #) -> unIO (ka) new_s 

unIO简单地从IO构造函数中解开函数。

需要注意的是, IO a表示可以运行以产生typesa的值的不纯计算的描述 。 事实上,有一种方法可以从GHC的IO内部表示中获得价值,这并不意味着这一般性地成立,也不意味着你可以为所有的单子做这样的事情。 这纯粹是GHC部分的实现细节。

1 状态monad是通过一系列计算来访问和变异状态的monad, 它被表示为s -> (a, s) (其中s是状态的types),看起来与GHC用于IO的types非常相似,因此是混淆。

你会失望的,但是IO >>= monad中的>>=并不是那么有趣。 引用GHC来源:

 {- | A value of type @'IO' a@ is a computation which, when performed, does some I\/O before returning a value of type @a@. There is really only one way to \"perform\" an I\/O action: bind it to @Main.main@ in your program. When your program is run, the I\/O will be performed. It isn't possible to perform I\/O from an arbitrary function, unless that function is itself in the 'IO' monad and called at some point, directly or indirectly, from @Main.main@. 'IO' is a monad, so 'IO' actions can be combined using either the do-notation or the '>>' and '>>=' operations from the 'Monad' class. -} newtype IO a = IO (State# RealWorld -> (# State# RealWorld, a #)) 

这意味着IO monad被声明为State State# monad的实例, 它的>>=在那里被定义(并且它的实现很容易猜到)

有关IO monad的更多详细信息,请参阅Haskell wiki上的IO文章。 查看Haskell文档也很有帮助,每个位置右侧都有一个小的“Source”链接。

更新:还有一个失望,那就是我的回答,因为我没有注意到State# 。 然而, IO行为就像携带抽象的RealWorld状态的State monad

正如@ehird所写的, State#是编译器的内部,而>>=IO monad是在GHC.Base模块中定义的:

 instance Monad IO where {-# INLINE return #-} {-# INLINE (>>) #-} {-# INLINE (>>=) #-} m >> k = m >>= \ _ -> k return = returnIO (>>=) = bindIO fail s = failIO s returnIO :: a -> IO a returnIO x = IO $ \ s -> (# s, x #) bindIO :: IO a -> (a -> IO b) -> IO b bindIO (IO m) k = IO $ \ s -> case ms of (# new_s, a #) -> unIO (ka) new_s 

他们没有做任何特别的事情,只是在那里进行sorting的行动。 如果你用不同的名字想到它们会有所帮助:

>> =变成“然后,使用前一个动作的结果”

>>变成“然后”

回报变成“什么也不做,但是无所事事的结果是”

这转动这个function:

 main :: IO () main = putStr "hello" >> return " world" >>= putStrLn 

变为:

 main :: IO () main = putStr "hello" and then, do nothing, but the result of doing nothing is " world" and then, using the result of the previous action, putStrLn 

最后,IO没有什么神奇的。 它和C中的分号一样神奇