我为一种简单的编程语言编写了一个解析器和评估器。这是 AST 类型的简化版本:
data Value = IntV Int | FloatV Float | BoolV Bool
data Expr = IfE Value [Expr] | VarDefE String Value
type Program = [Expr]
Run Code Online (Sandbox Code Playgroud)
我希望错误消息告诉发生错误的源代码的行和列。例如,如果If表达式中的值不是布尔值,我希望求值器显示一个错误,指出"expected boolean at line x, column y",x并y引用值的位置。
所以,我需要做的是重新定义之前的类型,以便它们可以存储不同事物的相关位置。一种选择是为表达式的每个构造函数添加一个位置,如下所示:
type Location = (Int, Int)
data Expr = IfE Value [Expr] Location | VarDef String Value Location
Run Code Online (Sandbox Code Playgroud)
这显然不是最优的,因为我必须将这些Location字段添加到每个可能的表达式中,例如,如果一个值包含其他值,我也需要为该值添加位置:
{-
this would turn into FunctionCall String [Value] [Location],
with one location for each value in …Run Code Online (Sandbox Code Playgroud) 我正在为一种小型编程语言编写一个解释器,AST 看起来像这样:
\ndata Value a = IntVal a Int | FloatVal a Float\ndata Expr a = AddExpr a (Value a) (Value a) | MulExpr a (Value a) (Value a)\nRun Code Online (Sandbox Code Playgroud)\n我使用参数a来存储每个术语的行号。有些函数采用带注释的术语,有些函数采用空术语(用 替换a)unit,如下所示:
myFunction :: Value Int -> ...\nmyFunction = ...\n\nmyOtherFunction :: Value () -> ...\nmyOtherFunction = ...\nRun Code Online (Sandbox Code Playgroud)\n然而,我发现这个替代方案更清晰一些:
\ntype Annotated b = b Int\ntype Bare b = b ()\nRun Code Online (Sandbox Code Playgroud)\n然后,我可以像这样重写前两个函数:
\nmyFunction :: Annotated Value -> ...\nmyFunction = ...\n\nmyOtherFunction …Run Code Online (Sandbox Code Playgroud) 我有这个简单的函数可以将用户的评论数量转换为成员类型。
function checkMemberN($numMessages){
$n= $numMessages;
switch ($n) {
case ($n<50): $type="New"; break;
case ($n>=50 && $n<250):$type="Frequent";break;
case ($n>=250 && $n<1000): $type="Master";break;
default: $type="undefinded";
}
return $type;
}
echo checkMemberN(0);
Run Code Online (Sandbox Code Playgroud)
看起来它不能识别零 (0),因为当我输入 1 或更高的数字时,它会检索正确的用户类型。我究竟做错了什么?