non*_*ont 44 monads logging haskell
我正在尝试使用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."
...
Run Code Online (Sandbox Code Playgroud)
这很好,因为函数在IO内部.但是,当我向以下函数添加类似的行时:
...
parsePES :: Parser PESFile
parsePES = do
header <- string "#PES"
warningM "parsing header"
...
return (PESFile ...)
Run Code Online (Sandbox Code Playgroud)
我收到类型错误:
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";
...
Run Code Online (Sandbox Code Playgroud)
我完全理解为什么 - parsePES在Parser monad中,而不是IO monad.我不明白的是该怎么做.我需要一个monad变换器,所以我可以将Parser monad和IO monad堆叠在一起吗?我该怎么做?
C. *_*ann 49
首先,快速免责声明:"日志记录"在一般的Haskell代码中通常没有意义,因为它假定某种顺序执行可能有意义也可能没有意义.确保区分记录程序执行方式和记录计算值.在严格的命令式语言中,这些语言基本相同,但在Haskell中则不然.
也就是说,听起来你想在已经连续和有状态的计算的上下文中基于计算的值进行记录,这几乎和大多数其他语言的记录一样.但是,你确实需要monad来支持这样做的一些方法.看起来你正在使用的解析器来自HCodecs包,它似乎相对有限,不允许IO,并且没有被定义为monad转换器.
老实说,我的建议是考虑使用不同的解析库.Parsec往往是一种默认选择,我认为attoparsec在特定目的(可能包括你正在做的事情)中很受欢迎.要么让你更容易添加日志记录:Parsec是一个monad转换器,所以你可以把它放在上面,IO然后liftIO根据需要使用,而attoparsec是围绕增量处理设计的,所以你可以对你的输入进行分块并记录处理的各个方面(虽然在实际的解析器中进行登录可能会更加尴尬).还有其他选择,但我不知道足够的细节来提出建议.大多数基于组合器的基于组合器的库往往具有相当类似的设计,因此我希望移植代码会很简单.
最后一个选项,如果你真的想坚持你所拥有的,那就是看看你现在正在使用的解析库的实现,并推出你自己IO的版本.但这可能并不理想.
另外,作为一个附录,如果您真正关注的是实际上没有记录,而只是跟踪程序的执行作为开发的一部分,您可能会发现GHCi中内置的调试器更有帮助,或者说是老式的通过Debug.Trace模块进行 printf调试.
编辑:好的,听起来你似乎有理由考虑滚动自己的变化.你最近想要的是ParserTmonad变压器.这是目前的定义Parser:
newtype Parser a = Parser { unParser :: S -> Either String (a, S) }
Run Code Online (Sandbox Code Playgroud)
类型S是解析器状态.请注意,这大致是硬编码版本StateT S (Either String) a:
newtype StateT s m a = StateT { runStateT :: s -> m (a,s) }
Run Code Online (Sandbox Code Playgroud)
...... Either String被视为错误monad的地方.该ErrorT单子转换做同样的事情:
newtype ErrorT e m a = ErrorT { runErrorT :: m (Either e a) }
Run Code Online (Sandbox Code Playgroud)
那么当前类型相当于StateT S (ErrorT String Identity),你想要的是什么StateT S (ErrorT String IO).
看起来模块中的大多数函数都没有弄乱Parsermonad 的内部,所以你应该能够简单地替换类型定义,提供适当的类型类实例,编写自己的runParser函数,并且好好去.
Woj*_*ilo 26
免责声明:我是Logger haskell框架的作者.
尽管McCann的答案非常详细,但并未说明Haskell在提出问题时缺乏通用的日志记录框架.HSLogger现在是一个标准,但它提供了非常基本的日志记录功能,同时速度慢且不可扩展.需要说明的是,以下是HSLogger的一些缺陷:
WriterT或其他解决方案不要弄乱你的代码.话虽如此,我很乐意介绍Logger haskell框架.它允许有效和可扩展的日志记录,包括:
WriterTmonad)TemplateHaskell允许记录其他详细信息的接口,例如文件编号或模块名称BaseLogger,它无法做任何明智的事情.需要明确的是 - 过滤功能在不到20行中创建,作为记录变压器,您可以定义自己的变压器.文档中描述了如何操作.但是这个库很新,所以它缺少一些必要的功能.好的信息是,您可以自己轻松创建此功能,或通过在GitHub上报告请求来帮助我们改进它.
记录器由我正在工作的公司(luna-lang.org)内部开发,并在我们正在创建的编译器中使用.
| 归档时间: |
|
| 查看次数: |
13004 次 |
| 最近记录: |