一个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中使用的每个函数创建类似的阴影函数。
我不介意这样做,但只是想知道是否有更好的,更少的锅炉式方法来实现同样的目标。
感激不尽的任何帮助:)
答案 0 :(得分:2)
Parsec允许用户通过解析器只使用
来携带状态addSym :: String -> Parsec String [String] ()
addSym = void . updateState . (:) -- append a string to the symbol list
type MyParser = Parsec String [String]
这将正确处理回溯。