Haskell递归问题,微小的解析器。 Expr的否定和表达

时间:2009-10-06 09:39:32

标签: haskell parsing

data Expr =  Var Char | Tall Int | Sum Expr Expr | Mult Expr Expr | Neg Expr | Let Expr Expr Expr
    deriving(Eq, Show) 

parseExpr :: String -> (Expr, String)

parseExpr ('*':'(':s) = (Mult x y, s'')
    where (x,',':s') = parseExpr s
          (y,')':s'') = parseExpr s'
parseExpr ('+':'(':s) = (Sum x y, s'')
    where (x,',':s') = parseExpr s
          (y,')':s'') = parseExpr s'
parseExpr (x : xs) | isDigit x = (Tall (digitToInt x), xs)
parseExpr (x:s) = (Var x,s) 
    where   x >= 'A' = True
        x <= 'Z' = True 

我的解析器在完成之前缺少两件事。从上面的数据类型缺少“Neg Expr”和“Expr Expr Expr”。第一部分是这样的:

parseExpr('-' 
parseExpr('l':'e':'t':x:'b':'e 

与数据类型一样,Let表达式以let开头并接受三个Expr。 我不知道如何写出这些最后的功能。任何帮助都将非常感谢。

我确实在这里提出了另外一个问题,here是该问题的链接。


以下是一个例子:

parseProg "let X be 4 in let Y be *(2 , X) in let Z be +(Y , X) in
+(+(X , Y) , Z)"
Let (Var 'X') (Tall 4) (Let (Var 'Y') (Mult (Tall 2) (Var 'X')) (Let
(Var 'Z') (Sum (Var 'Y') (Var 'X')) (Sum (Sum (Var 'X') (Var 'Y')) (Var
'Z'))))

1 个答案:

答案 0 :(得分:1)

表达式的这些部分的基本策略与其他操作的基本策略相同,只是您不必解析两个子表达式,而是解析一个或三个子表达式。对于let,它看起来像这样:

parseExpr ('l':'e':'t':s) = (Let x y z, s3)
    where (x, 'b':'e':s1) = parseExpr s
          (y, 'i':'n':s2) = parseExpr s1
          (z, s3)         = parseExpr s2

如果字符串以字母l开头,et取剩余字符串(s)并尝试从中解析表达式。这会产生表达式(x)和剩余的字符串。我们希望剩下的字符串以字母be开头。由于这应该跟随另一个表达式,我们再次将此字符串的其余部分(s2)提供给parseExpr以解析另一个表达式。等等。

唯一的问题是我们没有考虑可能将这些关键字分开的空格,例如“let”和“be”来自周围的表达式。简单的解决方案是在这些关键字之前/之后只需要一个空格,并在parseExpr中更改模式以明确包含这些空格,例如:

    where (x, ' ':'b':'e':' ':s1) = parseExpr s

更灵活的是添加dropSpaces :: String -> String函数,删除前导空格并在适当的位置调用。