Parsing 具有多个返回类型的解析器

Parsing 具有多个返回类型的解析器,parsing,haskell,Parsing,Haskell,我对能够管理多种类型的解析器有问题,例如,算术表达式的解析器。此时,我的解析器只接受输入整数: aexpr::解析器Int aexpr=aterm`CHAINEL`addOp aterm::语法分析器Int aterm=afactor`chainl`mulOp afactor::Parser Int afactor=parenP'('aexpr')' 做 s在设计DSL时,通常会定义一种新的数据类型,表示值可以具有的所有不同形状: data Value = I Int | D D

我对能够管理多种类型的解析器有问题,例如,算术表达式的解析器。此时,我的解析器只接受输入整数:

aexpr::解析器Int aexpr=aterm`CHAINEL`addOp aterm::语法分析器Int aterm=afactor`chainl`mulOp afactor::Parser Int afactor=parenP'('aexpr')' 做
s在设计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"
例如,您的
mulOp
addOp
实现可以在其实现中的某个地方调用
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

或者随便什么。

您可以使用
或Int-Float
作为返回类型,因此
解析器(或Int-Float)
。如果您返回的是整型值或浮点值,那么您已经编写了一个计算器(它进行解析以进行计算)。解析器将返回一个解析树或类似的树。(我知道这听起来像是在狡辩,但区别是有用的。)