prim* 是什么意思
既然你是从报告的角度来问这个问题,那么我们也从报告的角度来回答这个问题:
在 Haskell 中无法定义的原语,由以“prim”开头的名称表示,在模块 PreludeBuiltin 中以系统相关方式定义,此处未显示
这在Haskell2010 by the way 中仍然相同。
如何在 GHC 中实现
不过,您可以have a look at base's source 看看它是如何在 GHC 中实现的:
putChar :: Char -> IO ()
putChar c = hPutChar stdout c
从那里你将深入兔子洞。 hPutChar 怎么知道怎么打印东西?好吧,它没有。它仅“缓冲”并检查您是否可以编写:
hPutChar :: Handle -> Char -> IO ()
hPutChar handle c = do
c `seq` return ()
wantWritableHandle "hPutChar" handle $ \ handle_ -> do
hPutcBuffered handle_ c
写入是在writeCharBuffer 中完成的,它会填充一个内部缓冲区,直到它被填满(或到达一行——它实际上取决于缓冲区模式):
writeCharBuffer h_@Handle__{..} !cbuf = do
-- much code omitted, like buffering
bbuf'' <- Buffered.flushWriteBuffer haDevice bbuf'
-- more code omitted, like buffering
那么flushWriteBuffer 是在哪里定义的?它实际上是stdout 的一部分:
标准输出::句柄
标准输出 = unsafePerformIO $ 做
setBinaryMode FD.stdout
enc
mkHandle FD.stdout "
" WriteHandle True (Just enc)
nativeNewlineMode{-翻译换行符-}
(只是stdHandleFinalizer)没有
stdout :: FD
stdout = stdFD 1
文件描述符(FD)是BufferedIO的一个实例:
instance BufferedIO FD where
-- some code omitted
flushWriteBuffer fd buf = writeBuf' fd buf
而writeBuf 使用instance GHC.IO.Device.RawIO FD's write,而最终leads to:
writeRawBufferPtr loc !fd buf off len
| isNonBlocking fd = unsafe_write -- unsafe 可以,不能阻塞
|否则 = do r unsafe_write = do_write (c_write (fdFD fd) (buf `plusPtr` off) len)
safe_write = do_write (c_safe_write (fdFD fd) (buf `plusPtr` off) len)
我们可以在哪里看到c_safe_write 和c_write,它们通常是对 C 库函数的绑定:
foreign import capi unsafe "HsBase.h write"
c_write :: CInt -> Ptr Word8 -> CSize -> IO CSsize
所以,putChar 使用 write。至少在 GHC 的实施中。然而,该报告不需要该实现,因此允许另一个编译器/运行时使用其他功能。
TL;DR
GHC 的实现使用 write 和内部缓冲区来写入内容,包括单个字符。