我试图弄清楚如何IO
定义基本的Haskell函数,所以我使用了这个引用,我得到了putChar
函数定义:
putChar :: Char -> IO () putChar = primPutChar
但是,现在我无法在primPutChar
任何地方找到有关此功能的更多信息.也许它可能是指一个预编译的函数,可以作为共享对象的二进制文件?如果是这种情况,是否可以查看其源代码?
prim*
意思既然您在报告中提出这个问题,我们也会根据报告回答这个问题:
在Haskell中无法定义的基元,以"
prim
" 开头的名称表示,在模块中以系统相关的方式定义,PreludeBuiltin
此处未显示
顺便提一下,这在Haskell2010中仍然是相同的.
但是,您可以查看base
源代码,了解它在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
:
stdout :: Handle stdout = unsafePerformIO $ do setBinaryMode FD.stdout enc <- getLocaleEncoding mkHandle FD.stdout "" WriteHandle True (Just enc) nativeNewlineMode{-translate newlines-} (Just stdHandleFinalizer) Nothing
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
'swrite
,最终导致:
writeRawBufferPtr loc !fd buf off len | isNonBlocking fd = unsafe_write -- unsafe is ok, it can't block | otherwise = do r <- unsafe_fdReady (fdFD fd) 1 0 0 if r /= 0 then write else do threadWaitWrite (fromIntegral (fdFD fd)); write where do_write call = fromIntegral `fmap` throwErrnoIfMinus1RetryMayBlock loc call (threadWaitWrite (fromIntegral (fdFD fd))) write = if threaded then safe_write else unsafe_write 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实施中.但是,该报告不需要该实现,因此允许另一个编译器/运行时用户使用其他功能.
GHC的实现使用write
内部缓冲区来编写内容,包括单个字符.