使用 parsec 解析 sum 数据类型

标签 parsing haskell parsec

我试图找出如何以最好的方式解析 Haskell 中的和数据类型。这是我尝试的摘录

type Value = Int

data Operator = ADD | SUB | MUL | DIV | SQR deriving (Show)

toOperator :: String -> Maybe Operator
toOperator "ADD" = Just ADD
toOperator "SUB" = Just SUB
toOperator "MUL" = Just MUL
toOperator "DIV" = Just DIV
toOperator "SQR" = Just SQR
toOperator _     = Nothing

parseOperator :: ParsecT String u Identity () Operator
parseOperator = do
    s <- choice $ map (try . string) ["ADD", "SUB", "MUL", "DIV", "SQR"]
    case toOperator s of
        Just x  -> return x
        Nothing -> fail "Could not parse that operator."

这段代码实现了我想要的功能,但有一个明显的问题:它检查数据两次。一旦进入 choice $ map (try . string) ["ADD", "SUB", "MUL", "DIV", "SQR"] 行,然后通过 toOperator

我想要的是,如果字符串出现在列表中,则希望将其解析为 Operator ,否则失败。但我不知道如何以“干净”的方式做到这一点。

最佳答案

如果让 toOperator 直接参与 Parsec 解析过程,而不是让它成为一个单独发生的步骤,会更简单,因为这样“这个东西是否是有效的运算符”可以提供反馈解析过程。

对于这种特定情况,您正在解析的内容是一个零字段枚举,其构造函数名称与您正在解析的字符串完全匹配,已经发布了几个很好的快捷方式,向您展示如何简洁地解析这些构造函数。在这个答案中,我将展示一种替代方法,它更容易适应“匹配几种情况之一”的一般情况,并处理更奇特的东西,例如“三个构造函数之一具有 Int 参数,但其他构造函数没有”

operator :: StringParser Operator
operator = string "ADD" *> pure ADD
       <|> string "DIV" *> pure DIV 
       <|> string "MUL" *> pure MUL
       <|> try (string "SUB") *> pure SUB 
       <|> string "SQR" *> pure SQR

现在假设您有一个额外的构造函数 VAR,它采用 String 参数。向此解析器添加对该构造函数的支持很容易:

operator :: StringParser Operator
operator = ...
       <|> string "VAR" *> (VAR <$> var)

var :: StringParser String
var = spaces *> anyChar `manyTill` space

关于使用 parsec 解析 sum 数据类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49758970/

相关文章:

java - 使用 split 解析分隔文本文件

haskell - 找出 Haskell 函数的复杂性

Haskell 中的 HTTP POST 内容

在 Haskell 的 Parsec 中解析基于缩进的语法

php - 读取txt文件并解析文本

javascript - 加载文件并解析文档

vba - 优化Vba代码

haskell - 模板 Haskell 引用中的独立派生声明

haskell - 如何使用秒差距解析一行?

haskell - 编写可选的 Aeson 解析器