【问题标题】:Haskell primPutChar definitionHaskell primPutChar 定义
【发布时间】:2016-04-02 05:16:09
【问题描述】:

我试图弄清楚基本的IO Haskell 函数是如何定义的,所以我使用了this reference 并得到了putChar 函数定义:

putChar    :: Char -> IO ()
putChar    =  primPutChar

但是,现在我无法在任何地方找到有关此primPutChar 函数的更多信息。也许它可能指的是预编译的函数,可作为共享对象的二进制文件?如果是这样,是否可以看到它的源代码?

【问题讨论】:

  • 函数名以prim开头表示它是一个内置的原语。这种函数的定义不能用 Haskell 给出;它也会在目标平台之间有所不同。有时它是一个外来函数,有时它是编译器熟知的函数名称(以便它可以直接在调用函数的地方发出适当的代码)。
  • @AndreyChernyakhovskiy 将您的答案作为答案,而不是评论。
  • 您可以在基本包中看到它:hackage.haskell.org/package/base-4.8.1.0/docs/src/… 感谢最新的黑线鳕,您可以轻松浏览它!
  • @Sibi 谢谢,这真的很有趣!但是,为什么在那个地方 putChar 是用 Haskell 代码定义的,并且在在线报告中他们暗示它是一个原始函数,正如 @AndreyChernyakhovskiy 指出的那样?前者是否编译一次然后在库中发布?编辑@Zeta 刚刚用答案击败了我 :)

标签: haskell io definition


【解决方案1】:

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_writec_write,它们通常是对 C 库函数的绑定:

foreign import capi unsafe "HsBase.h write"
   c_write :: CInt -> Ptr Word8 -> CSize -> IO CSsize

所以,putChar 使用 write。至少在 GHC 的实施中。然而,该报告不需要该实现,因此允许另一个编译器/运行时使用其他功能。

TL;DR

GHC 的实现使用 write 和内部缓冲区来写入内容,包括单个字符。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-05-28
    • 2018-11-20
    • 2011-05-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多