`traceIO`和`hPutStrLn stderr`有什么区别?

xzh*_*zhu 6 debugging haskell

看一下这个描述traceIO,我觉得它确实hPutStrLn stderr做到了.但是,当我查看其源代码时:

traceIO :: String -> IO ()
traceIO msg = do
    withCString "%s\n" $ \cfmt -> do
     -- NB: debugBelch can't deal with null bytes, so filter them
     -- out so we don't accidentally truncate the message.  See Trac #9395
     let (nulls, msg') = partition (=='\0') msg
     withCString msg' $ \cmsg ->
      debugBelch cfmt cmsg
     when (not (null nulls)) $
       withCString "WARNING: previous trace message had null bytes" $ \cmsg ->
         debugBelch cfmt cmsg
Run Code Online (Sandbox Code Playgroud)

它似乎使用了一个外部例程debugBelch,我没有找到任何文档.那么traceIO做不了什么hPutStrLn stderr呢?

Ørj*_*sen 5

我能想到的一件事是,它可以确保将字符串作为一个单元打印,而内部没有任何其他跟踪消息。事实上,一项实验似乎证实了这一点:

Prelude Debug.Trace System.IO> traceIO $ "1" ++ trace "2" "3"
2
13
Prelude Debug.Trace System.IO> hPutStrLn stderr $ "1" ++ trace "2" "3"
12
3
Run Code Online (Sandbox Code Playgroud)

另一个区别是它似乎删除了不能安全打印到 stderr 的字符:

Prelude Debug.Trace System.IO> hPutStrLn stderr "\9731"
*** Exception: <stderr>: hPutChar: invalid argument (invalid character)
Prelude Debug.Trace System.IO> traceIO "\9731"

Prelude Debug.Trace System.IO> 
Run Code Online (Sandbox Code Playgroud)

正如@dfeuer 提醒我的那样,这些功能中没有一个是不可能用 Haskell 编写的。所以决定因素可能是这样的:debugBelch已经是一个预定义的 C 函数,在 GHC 的运行时系统中到处使用,它是用 C 和 C 编写的——而不是 Haskell。