Parsing 具有多个返回类型的解析器
我对能够管理多种类型的解析器有问题,例如,算术表达式的解析器。此时,我的解析器只接受输入整数: aexpr::解析器Int aexpr=aterm`CHAINEL`addOp aterm::语法分析器Int aterm=afactor`chainl`mulOp afactor::Parser Int afactor=parenP'('aexpr')' 做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
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)
。如果您返回的是整型值或浮点值,那么您已经编写了一个计算器(它进行解析以进行计算)。解析器将返回一个解析树或类似的树。(我知道这听起来像是在狡辩,但区别是有用的。)