将WriterT与Parsec一起使用的最佳方法是什么?

时间:2013-10-22 15:47:51

标签: haskell monads parsec monad-transformers

一个noob Haskell问题。

我很高兴用Parsec和AttoParsec编写一些解析器。我现在想在解析过程中收集信息(基本上构建一个符号表),使用WriterT monad转换器似乎是一个不错的选择。

我现在正在使用这个简单的例子:

module NewParse where

import qualified Text.ParserCombinators.Parsec as A
import Control.Monad.Trans (lift)
import Control.Monad.Writer (WriterT, tell,  runWriterT)
type WParser a = WriterT [String] A.Parser a 

data StoryToken = StoryToken Char deriving (Show)

getToken :: WParser StoryToken
getToken = do
  tell ["hello from Writer T"]
  c <- lift A.anyChar 
  return $ StoryToken c 

test = A.parse (runWriterT getToken) "story" "#"

效果很好。在ghci中调用测试给了我:

*NewParse> test
Right (StoryToken '#',["hello"])

将此应用于我的解析器代码时,我有点害怕,因为每次调用它都需要解析解析器monad。我会相对不频繁地调用,但解析器功能很多。代码会变得更加丑陋。

有没有办法轻松地从Parsec中暴露某些功能,所以我不必在代码中使用lift?

对我有用的解决方案是创建我自己的功能

anyChar = lift A.anyChar

这很酷但是需要为我在parsec中使用的每个函数创建类似的阴影函数。

我不介意这样做,但只是想知道是否有更好的,更少的锅炉式方法来实现同样的目标。

感激不尽的任何帮助:)

1 个答案:

答案 0 :(得分:2)

Parsec允许用户通过解析器只使用

来携带状态
addSym :: String -> Parsec String [String] ()
addSym = void . updateState . (:) -- append a string to the symbol list

type MyParser = Parsec String [String]

这将正确处理回溯。