我正在试图弄清楚如何定义基本的IO
Haskell函数,所以我使用了this reference并且我得到了putChar
函数定义:
putChar :: Char -> IO ()
putChar = primPutChar
但是,现在我无法在任何地方找到有关此primPutChar
函数的更多信息。也许它可能是指一个预编译的函数,可以作为共享对象的二进制文件?如果是这种情况,是否可以查看其源代码?
答案 0 :(得分:10)
prim*
的含义由于您在报告中提出这个问题,我们也会根据报告回答这个问题:
在Haskell中无法定义的基元,由以“
prim
”开头的名称表示,在模块PreludeBuiltin
中以系统相关的方式定义,并且未在此处显示
Haskell2010 by the way中的情况仍然相同。
但是,您可以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
的一部分:
stdout :: Handle stdout = unsafePerformIO $ do setBinaryMode FD.stdout enc <- getLocaleEncoding mkHandle FD.stdout "<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
's write
,最终使用leads to:
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
和内部缓冲区来编写内容,包括单个字符。