【发布时间】:2019-05-13 17:51:48
【问题描述】:
我想知道 putStrLn 是如何工作的:我可以看到它的类型为 IO (),但我不知道 Haskell 是如何实际执行写入标准输出的副作用的。
main :: IO ()
main = putStrLn "Test"
这个程序如何写入标准输出?
【问题讨论】:
我想知道 putStrLn 是如何工作的:我可以看到它的类型为 IO (),但我不知道 Haskell 是如何实际执行写入标准输出的副作用的。
main :: IO ()
main = putStrLn "Test"
这个程序如何写入标准输出?
【问题讨论】:
看到base那个
putStrLn s = hPutStrLn stdout s
我跟踪了一系列函数,最终将我引向c_write,其定义如下:
foreign import capi unsafe "HsBase.h _write"
c_write :: CInt -> Ptr Word8 -> CUInt -> IO CInt
这样看来,写入stdout的效果是通过调用native code来实现的。
在我从一个函数跳到另一个函数的旅程中的一些停靠点(箭头→表示左边的函数调用右边的函数):
hPutStr' → writeBlocks → commitBuffer → writeCharBuffer。
然后,writeCharBuffer 在stdout 上调用类型类方法BufferedIO.flushWriteBuffer。
在stdout's typeclass instance 继续BufferedIO:
flushWriteBuffer → writeBuf' → writeBuf。 writeBuf 在RawIO 设备上调用IODevice.write,这也是一个有instance for stdout 的类型类。 write 中继到fdwrite。
fdWrite 调用writeRawBufferPtr → do_write 最后调用c_write。
【讨论】:
putStrLn 是唯一由 Haskell 定义的东西。下面的所有内容,在本例中从hPutStrLn 开始,都是 GHC 的实现细节。