【问题标题】:Parser with multiple return types具有多种返回类型的解析器
【发布时间】:2019-12-23 17:58:11
【问题描述】:

我对可以管理多种类型的解析器有问题,例如算术表达式的解析器。目前我的解析器只输入整数:

aexpr :: Parser Int
aexpr = aterm `chainl` addOp

aterm :: Parser Int
aterm = afactor `chainl` mulOp

afactor :: Parser Int
afactor = parenP '(' aexpr ')'
          <|>
          do
            s <- sign 
            a <- aexpr 
            return (s * a)
          <|>  
          token int_const

这适用于两个整数,但我引入了浮点类型,因此算术表达式的解析器可以在输入中输入两个Int、两个FloatIntFloat 的两种混合类型。根据输入,解析器的结果类型应为IntFloat(即,如果两个输入均为Int,则为Int,否则为Float)。

我的问题是:管理此问题的最佳方法是什么?一种简单的方法是将所有输入管理为Float,因此整数值将转换为浮点值。但我不喜欢这种解决方案:最终结果将始终是Float

我是否应该创建两个不同的解析器,即一个用于Int,一个用于Float?但是这两个解析器几乎是一样的。

有更好的解决方案吗?

【问题讨论】:

  • 你可以使用Either Int Float作为返回类型,所以Parser (Either Int Float)
  • 如果您要返回一个整数或浮点值,您已经编写了一个求值器(它会解析以求值)。解析器将返回解析树或类似的东西。 (我知道这听起来像是一个狡辩,但这种区别很有用。)

标签: parsing haskell


【解决方案1】:

在设计 DSL 时,定义一个新的数据类型来表示值可以具有的所有不同形状是很常见的:

data Value
    = I Int
    | D Double
    deriving (Eq, Ord, Read, Show)

您可能想要实现一些辅助函数,例如:

binOp :: (forall a. Num a => a -> a -> a) -> Value -> Value -> Parser Value
binOp f (I a) (I b) = pure (I (f a b))
binOp f (D a) (D b) = pure (D (f a b))
binOp _ _ _ = fail "oof, tried to mix Ints and Doubles"

然后,您的 mulOpaddOp 实现可以在其实现中的某处调用 binOp (*)binOp (+)

但我会考虑另一种方法,而不是直接使用此类助手。我建议引入一个解析“总是成功”的中间表示,然后添加一个单独的类型检查阶段,您可以在其中抛出有关混合整数和双精度数的错误......或者进行适当的强制转换,或者您的 DSL 想要在那里发生的任何事情。所以:

data BinOp = Plus | Times deriving (Bounded, Enum, Eq, Ord, Read, Show)
data Type = Int | Double deriving (Bounded, Enum, Eq, Ord, Read, Show)
data DSL
    = ILit Int
    | DLit Double
    | BinOp BinOp DSL DSL
    deriving (Eq, Ord, Read, Show)

然后你可以用类似的类型写东西

typeCheck :: DSL -> These [TypeError] Type -- check for mixing
unsafeEval :: DSL -> Value -- implementation uses incomplete patterns and assumes no mixing

eval :: DSL -> Either [TypeError] Value
eval t = case typeCheck t of
    That _ -> Right (unsafeEval t)
    These [] _ -> Right (unsafeEval t)
    These es _ -> Left es
    This es -> Left es

或其他。

【讨论】:

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