【问题标题】:Custom state in TrifectaTrifecta 中的自定义状态
【发布时间】:2013-09-14 21:30:21
【问题描述】:

我正在使用Trifecta 解析器组合库,我的解析器输出 AST 数据类型的实例。我希望每个实例都有唯一的 ID(简单的 Int)。

在 Parsec 中,我会创建自定义状态并在必要时增加 ID。我们如何在 Trifecta 中做到这一点?

【问题讨论】:

    标签: parsing haskell monads parser-combinators trifecta


    【解决方案1】:

    您可以使用 StateT monad 转换器增强 Parser monad 以获得您想要的。这与库的其余部分很好地集成在一起,因为大多数组合器使用类型类而不是具体类型(这意味着您不必为代码工作做太多的提升)。这是一个很好的例子。它解析带有由空格分隔的标识符和符号的语法。每个标识符都有一个唯一的编号。

    module Main where
    import Text.Trifecta
    import Control.Monad.State
    import Control.Applicative
    import Data.Monoid
    
    data Identifier = Identifier String Int deriving (Show)
    
    identifier :: StateT Int Parser Identifier
    identifier = do
      name <- some letter
      newId <- get
      modify (+1)
      return $ Identifier name newId
    
    symbolToken :: Parser Char
    symbolToken = oneOf "+-*/"
    
    data Token = IdentifierToken Identifier | SymbolToken Char deriving (Show)
    
    singleToken :: StateT Int Parser Token
    singleToken = try (IdentifierToken <$> identifier) <|> (SymbolToken <$> lift symbolToken)
    
    parseTokens :: StateT Int Parser [Token]
    parseTokens = singleToken `sepBy1` spaces
    
    testParse :: String -> Result [Token]
    testParse = parseString (evalStateT parseTokens 0) mempty 
    
    test1 :: Result [Token]
    test1 = testParse "these are identifiers and + some / symbols -"
    

    test1 结果:

    Success [IdentifierToken (Identifier "these" 0)
    ,IdentifierToken (Identifier "are" 1)
    ,IdentifierToken (Identifier "identifiers" 2)
    ,IdentifierToken (Identifier "and" 3)
    ,SymbolToken '+',IdentifierToken (Identifier "some" 4)
    ,SymbolToken '/',IdentifierToken (Identifier "symbols" 5),SymbolToken '-']
    

    【讨论】:

    • 我刚刚发现答案是错误的。看,你在解析之前评估状态,这是错误的 - 在这样的用例中,如果你想使用状态来生成唯一标识符。
    • 您确定这不正确吗?状态不仅在一开始就被评估,而是通过整个程序进行评估。 evalStateT parseTokens 0 实际上只是设置初始状态值。我一直都是这样做的,而且似乎没有任何问题。如果您确实有一个示例说明这如何产生意想不到的结果,我希望看到它!
    • 对,我错了。这个例子是有效的——我们的例子在一个非常有趣的地方有一个错字,我们在完全错误的地方寻找错误。我明天将删除 cmets,因为它们现在已经过时了。谢谢! :)
    猜你喜欢
    • 1970-01-01
    • 2021-06-24
    • 2021-03-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-10
    • 1970-01-01
    相关资源
    最近更新 更多