data Expr = Var Char | Tall Int | Sum Expr Expr | Mult Expr Expr | Neg Expr | Let Expr Expr Expr
deriving(Eq, Show)
这是Expr
的数据类型,我有几个问题。我想要解析像*(Expr,Expr)
这样的表达式,如数据类型定义中所示。但是我在“创建”有效Expr
时遇到了一些问题。我使用模式匹配来识别Expr可以做的不同事情。还有一些代码:
parseExpr :: String -> (Expr, String)
parseExpr ('*':'(':x:',':y:')':s) = (Mult (parseExpr [x] parseExpr [y]),s)
显然这不起作用。 parseExpr
的返回类型是将要解析的表达式的其余部分作为Expr
返回到已解析代码的一部分。这段代码的右侧是问题所在。我无法建立有效的Expr
。该函数假设以递归方式调用它,直到问题解决。
另一个问题是我不知道如何对Var
和Tall
进行模式匹配。如何检查Var
是A-Z之间的大写字符,而Tall
是0-9并将其作为有效Expr
返回?
通常我可以查看字符串的一些部分来理解我正在处理的Expr
的哪个部分。
Input like: parseProg "let X be 9 in *(X , 2)" Would spit out: Let (Var 'X') (Tall 9) (Mult (Var 'X') (Tall 2))
答案 0 :(得分:2)
您的parseExpr
函数返回一对,因此您无法直接使用其结果来构造Expr
。我写这个的方式就像
parseExpr ('*':'(':s) = (Mult x y, s'')
where (x,',':s') = parseExpr s
(y,')':s'') = parseExpr s'
基本思想是,由于parseExpr
返回剩余字符串作为该对的第二个参数,您需要在每个递归调用中保存该字符串,并且当您处理完所有子表达式时,你需要归还剩下的东西。显然,这里的错误处理很糟糕,所以如果想要成为一个强大的解析器,你可能想要考虑更多。
处理Var
和Tall
我只需按原样提取第一个字符并使用if
来构建相应类型的Expr
。
如果你想在Haskell中编写更复杂的解析器,你需要查看Parsec库,它允许你编写一个解析器,就像你正在解析的语言的语法一样。