在Haskell中编写一个小解析器的递归问题。检查变量

时间:2009-10-07 22:17:23

标签: parsing haskell interpreter evaluation

我还在研究一种小型解析器,用于学校任务中​​定义的小语言。生成AST(抽象语法树)的解析器正在运行。我想要的是检查已定义的变量,它们必须以let表达式为界。首先是任务中定义的方法(建议,不需要):

checkVars :: Expr -> Char 

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

有效句子是“让X为5 in *(2,X)”。 X通常是Var,5通常是int。最后一个可以是dataExpr类型的任何部分。要点: X在最后一个表达式的某处使用。 let的数据类型为:

Let Expr Expr Expr

仅仅在这里,我就这个问题与我提出的其他问题联系起来。 First question Second question

正如您看到checkVars的数据类型是Expr,所以这里是我将要为该函数提供的示例:

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'))))
Just 24

这是一个包罗万象的例子,顶部是要解析的字符串/程序。第二部分,从第3行(Let)开始是AST,checkVars函数的输入。底部“Just 24”就是评价。我将回到这里寻求更多帮助。 注意:重点是吐出第一个被发现为错误的未绑定变量,并且''如果一切正常。显然,如果你想以另一种方式做到这一点。

2 个答案:

答案 0 :(得分:5)

这是需要考虑的事情:

Let构造函数的第一个字段是Expr。但除了Var之外,它还能保留其他东西吗?如果没有,你应该通过制作该字段的类型来反映这一点,例如String并相应地调整解析器。这将使您的任务变得更加容易。

使用let-bindings(你正在做)评估表达式的标准技巧是编写一个函数

type Env = [(String, Int)]
eval :: Expr -> Env -> Int

请注意环境的额外参数。环境会跟踪在任何给定时刻绑定到哪些变量的值。它在类型中的位置意味着每次在子表达式上调用eval时都可以决定它的值。这至关重要!它还意味着您可以拥有本地声明的变量:绑定变量对其上下文没有影响,仅在子表达式上。

以下是特殊情况:

  • Var中,您希望lookup环境中的变量名称并返回绑定到它的值。 (使用标准的前奏函数lookup。)
  • Let中,您希望在将其传递给子表达式之前,在环境列表的前面添加一个额外的(varname, value)

我遗漏了一些细节,但这应该足以让你走得很远。如果你遇到困难,请问另一个问题。 : - )

哦,我发现你想要返回一个Maybe值来表示失败。我建议你首先尝试不使用error来表示未绑定的变量。如果您的eval版本正常工作,请将其修改为返回Maybe值。这样做的原因是使用Maybe值会使评估变得更加复杂。

答案 1 :(得分:0)

我实际上会尝试评估 AST。首先处理(并因此删除)所有Let s。现在,尝试评估生成的AST。如果您遇到Var,那么就会有一个未绑定的变量。