【问题标题】:How do I generalize a Parser which extracts values from tokens?如何概括从标记中提取值的解析器?
【发布时间】:2021-09-11 03:50:24
【问题描述】:

我正在用 Haskell 为一种简单的语言创建一个解析器。解析器获取由单独的标记器生成的标记列表,并将其转换为结构化树。在编写此 Parser 时,我遇到了一个我想概括的重复出现的模式。以下是相关定义:

--Parser Definition
data Parser a b = Parser { runParser :: [a] -> Maybe ([a], b) }

--Token Definition
data Token = TokOp    { getTokOp :: Operator }
           | TokInt   { getTokInt :: Int }
           | TokIdent { getTokIdent :: String }
           | TokAssign
           | TokLParen
           | TokRParen
   deriving (Eq, Show)

解析器还为 MonadPlus 及其所有超类定义了实例。以下是我试图概括的重复出现模式的两个示例:

-- Identifier Parser
identP :: Parser Token String
identP = Parser $ \input -> case input of
  TokIdent s : rest -> Just (rest, s)
  _                 -> Nothing

--Integer Parser
intP :: Parser Token Int
intP = Parser $ \input -> case input of
  TokInt n : rest -> Just (rest, n)
  _               -> Nothing

如您所见,这两个示例非常相似,但我认为无法一概而论。理想情况下,我想要一些 extractToken :: ?? -> Parser Token a 类型的函数,其中 a 是令牌包含的值。我猜该解决方案涉及>>=,但我对 Monads 的经验不足,无法弄清楚。这也可能是不可能的,我不确定。

【问题讨论】:

  • 如果我建议像(a -> Maybe b) -> Parser a b 这样的类型,是否足以弄清楚该怎么做?
  • 是的,这是有道理的。您正在描述以下答案(由 K. A. Buhr 撰写的答案)所说的更通用的版本,对吗?
  • 是的,我就是这么想的。

标签: parsing haskell functional-programming token monads


【解决方案1】:

似乎很难避免至少一些样板。一种简单的方法是手动定义字段选择器以返回Maybes:

{-# LANGUAGE LambdaCase #-}

data Token = TokOp Operator
           | TokInt Int
           | TokIdent String
           | TokAssign
           | TokLParen
           | TokRParen
   deriving (Eq, Show)

getTokOp    = \case { TokOp x    -> Just x ; _ -> Nothing }
getTokInt   = \case { TokInt x   -> Just x ; _ -> Nothing }
getTokIdent = \case { TokIdent x -> Just x ; _ -> Nothing }

然后剩下的就是:

fieldP :: (Token -> Maybe a) -> Parser Token a
fieldP sel = Parser $ \case tok:rest -> (,) rest <$> sel tok
                            []       -> Nothing

opP    = fieldP getTokOp
identP = fieldP getTokIdent
intP   = fieldP getTokInt

您可以使用 Template Haskell 或泛型派生 getXXX 选择器,尽管这可能不值得。

【讨论】:

    猜你喜欢
    • 2021-07-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-11
    • 2017-05-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多