Haskell primPutChar 定义 [英] Haskell primPutChar definition

查看:14
本文介绍了Haskell primPutChar 定义的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

putChar :: Char ->输入口 ()putChar = primPutChar

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

解决方案

prim* 的含义

既然你是从报告的角度问这个问题,那我们也从报告的角度来回答这个问题:

<块引用>

无法在 Haskell 中定义的原语,由以prim"开头的名称表示,在模块 PreludeBuiltin 中以系统相关的方式定义,此处未显示

顺便说一下,这在 Haskell2010 中还是一样的.

它是如何在 GHC 中实现的

但是,您可以有查看 base 的源代码,了解它是如何在 GHC 中实现的:

putChar :: Char ->输入口 ()putChar c = hPutChar 标准输出 c

从那里您将深入兔子洞.hPutChar 知道怎么打印东西吗?好吧,它没有.它只缓冲"并检查您是否可以编写:

hPutChar :: 句柄 ->字符 ->输入口 ()hPutChar 句柄 c = doc`seq`返回()wantWritableHandle "hPutChar" 句柄 $handle_ ->做hPutcBuffered handle_ c

写在writeCharBuffer 填充一个内部缓冲区直到它满(或者已经到达一行——这实际上取决于缓冲模式):

writeCharBuffer h_@Handle__{..} !cbuf = do-- 省略了很多代码,比如缓冲bbuf'' <- Buffered.flushWriteBuffer haDevice bbuf'-- 省略了更多代码,例如缓冲

那么flushWriteBuffer 定义了吗?它实际上是 的一部分标准输出:

<前>标准输出::句柄标准输出 = unsafePerformIO $ 做setBinaryMode FD.stdoutenc <- getLocaleEncodingmkHandle FD.stdout ""WriteHandle True(仅加密)nativeNewlineMode{-translate newlines-}(只是 stdHandleFinalizer)没什么

stdout :: FD标准输出 = 标准FD 1

文件描述符 (FD) 是 BufferedIO:

instance BufferedIO FD where-- 省略了一些代码flushWriteBuffer fd buf = writeBuf' fd buf

writeBuf 使用 实例GHC.IO.Device.RawIO FDwrite,最终导致:

<前>writeRawBufferPtr loc !fd buf off len|isNonBlocking fd = unsafe_write -- unsafe 没问题,不能阻塞|否则 = do r <- unsafe_fdReady (fdFD fd) 1 0 0如果 r/= 0然后写否则做 threadWaitWrite (fromIntegral (fdFD fd));写在哪里do_write call = fromIntegral `fmap`throwErrnoIfMinus1RetryMayBlock loc 调用(threadWaitWrite (fromIntegral (fdFD fd)))写=如果线程然后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_writec_write,它们通常是C库函数的绑定:

国外进口capi不安全HsBase.h写"c_write :: CInt ->Ptr Word8 ->CSize ->IO CS大小

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

TL;DR

GHC 的实现使用带有内部缓冲区的 write写东西,包括单个字符.

I'm trying to figure out how the basic IO Haskell functions are defined, so I used this reference and I got to the putChar function definition:

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

Now, however, I cannot find more information about this primPutChar function anywhere. Maybe it might refer to a pre-compiled function, available as binary from a shared object? If that's the case, is it possible to see its source code?

解决方案

What prim* means

Since you're asking this question in terms of the report, let's also answer this question in terms of the report:

Primitives that are not definable in Haskell , indicated by names starting with "prim", are defined in a system dependent manner in module PreludeBuiltin and are not shown here

This is still the same in Haskell2010 by the way.

How it's implemented in GHC

However, you can have a look at base's source to see how it's implemented in GHC:

putChar         :: Char -> IO ()
putChar c       =  hPutChar stdout c

From there you're going deep into the rabbit hole. How does hPutChar know how to print stuff? Well, it doesn't. It only "buffers" and checks that you can write:

hPutChar :: Handle -> Char -> IO ()
hPutChar handle c = do
    c `seq` return ()
    wantWritableHandle "hPutChar" handle $  handle_  -> do
     hPutcBuffered handle_ c

The writing is done in writeCharBuffer which fills an internal buffer until it's full (or a line has been reached—it actually depends on the buffer mode):

writeCharBuffer h_@Handle__{..} !cbuf = do
  -- much code omitted, like buffering
      bbuf'' <- Buffered.flushWriteBuffer haDevice bbuf'
  -- more code omitted, like buffering

So where is flushWriteBuffer defined? It's actually part of 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

And a file descriptor (FD) is an instance of BufferedIO:

instance BufferedIO FD where
  -- some code omitted
  flushWriteBuffer  fd buf = writeBuf' fd buf

and writeBuf uses instance GHC.IO.Device.RawIO FD's write, and that ultimately 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)

where we can see c_safe_write and c_write, which are usually bindings to C library functions:

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

So, putChar uses write. At least in GHC's implementation. The report however doesn't require that implementation, so another compiler/runtime is allowed to use other functions.

TL;DR

GHC's implementation uses write with internal buffers to write things, including single characters.

这篇关于Haskell primPutChar 定义的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆