gpt4 book ai didi

logging - 如何登录 Haskell?

转载 作者:行者123 更新时间:2023-12-02 08:40:20 25 4
gpt4 key购买 nike

我正在尝试使用 HSlogger 来获取有关我的程序的一些信息。所以我将以下行添加到我的函数中

import Data.Word
import qualified Data.ByteString as B
import qualified Data.ByteString.Lazy as L
import Data.Bits
import Data.Int
import Data.ByteString.Parser

import System.Log.Logger
import System.Log.Handler.Syslog


importFile :: FilePath -> IO (Either String (PESFile ))
importFile n = do
warningM "MyApp.Component2" "Something Bad is about to happen."
...

效果很好,因为该函数位于 IO 内部。但是,当我向以下函数添加类似的行时:

...
parsePES :: Parser PESFile
parsePES = do
header <- string "#PES"
warningM "parsing header"
...
return (PESFile ...)

我收到类型错误:

 Couldn't match expected type `Parser a0'
with actual type `String -> IO ()'
In the return type of a call of `warningM'
In a stmt of a 'do' expression: warningM "parsing header"
In the expression:
do { header <- string "#PES";
warningM "parsing header";
...

我完全理解为什么 - parsePES 位于解析器 monad 中,而不是 IO monad 中。我不明白的是该怎么办。我是否需要一个 monad 转换器才能将 Parser monad 和 IO monad 堆叠在一起?我该怎么做?

最佳答案

首先,快速免责声明:“日志记录”在一般 Haskell 代码中通常没有意义,因为它假设某种顺序执行,可能有意义也可能没有意义。确保区分记录程序如何执行记录计算的值。在严格的命令式语言中,这些大多是相同的,但在 Haskell 中则不然。

也就是说,听起来您想在已经是顺序且有状态的计算的上下文中基于正在计算的值进行日志记录,这与大多数其他语言中的日志记录几乎相同。但是,您确实需要 monad 来支持某些这样做的方法。看起来您正在使用的解析器是 from the HCodecs package ,似乎比较有限,不允许 IO ,并且没有定义为 monad 转换器。

老实说,我的建议是考虑使用不同的解析库。 Parsec往往是默认选择,我认为 attoparsec因特定目的而流行(可能包括您正在做的事情)。两者都可以让您更轻松地添加日志记录:Parsec 是一个 monad 转换器,因此您可以将其放在 IO 之上然后使用 liftIO根据需要,而 attoparsec 是围绕增量处理设计的,因此您可以对处理的输入和日志方面进行分块(尽管在实际解析器内进行日志记录可能会更尴尬)。还有其他选择,但我不知道足够的细节来提出建议。大多数基于解析器组合器的库往往具有相当相似的设计,因此我希望移植您的代码会很简单。

如果您真的想坚持现有的,最后一个选择是查看您现在使用的解析库的实现并推出您自己的 IO它的面向版本。但这可能并不理想。

<小时/>

此外,作为附录,如果您真正想要的不是实际日志记录,而只是作为开发的一部分跟踪程序的执行,您可能会发现 GHCi 中内置的调试器更有帮助,或者更好通过 the Debug.Trace module 进行老式 printf 调试.

<小时/>

编辑:好的,听起来您有合理的理由考虑推出自己的变体。您在这里大致想要的是 ParserT单子(monad)变压器。这是 Parser 的当前定义:

newtype Parser a = Parser { unParser :: S -> Either String (a, S) }

类型S是解析器状态。请注意,这大致是 StateT S (Either String) a 的硬编码版本。 :

newtype StateT s m a = StateT { runStateT :: s -> m (a,s) }

...哪里Either String被视为错误单子(monad)。 ErrorT monad 转换器做同样的事情:

newtype ErrorT e m a = ErrorT { runErrorT :: m (Either e a) }

当前类型相当于 StateT S (ErrorT String Identity) ,你想要的是 StateT S (ErrorT String IO) .

看起来模块中的大多数功能都没有扰乱 Parser 的内部结构。 monad,所以您应该能够简单地替换类型定义,提供适当的类型类实例,编写您自己的 runParser功能正常,然后就可以开始使用了。

关于logging - 如何登录 Haskell?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6310961/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com