haskell - Haskell:将任何 Ast 评估为字符串
问题描述
我有一个分配,我必须编写一个评估函数 eval::Ast -> String ,它将任何 Ast 评估为一个字符串。例如:
>eval (parse "hel + lo")
"hello"
> eval (parse "mi + 2 * la")
"milala"
我制作了一个解析函数,例如采用“hel + lo”并返回 Plus (Word "hel") (Word "lo")
但是我非常不确定函数(和类型)应该是什么样子,因为 AST 的评估涉及多种类型......谁能让我朝着正确的方向前进?
AST 定义为
data Ast
= Word String
| Num Int
| Mult Ast Ast
| Plus Ast Ast
| Minus Ast Ast
deriving (Eq, Show)
解决方案
eval :: AST -> String
是什么定义了你的操作的语义。例如,eval (Plus (Word x) (Word y)) == x ++ y
。
eval (Plus x y)
但是,如果两个参数都是数字,应该产生什么?它应该连接它们,还是以数字方式添加它们?如果其中任何一个本身是 、 或 值之一Plus
怎么Minus
办Mul
?您需要首先评估它们,但是您无法判断结果"2"
是真的是字符串还是数字的结果。
您还需要确定是否AST
可以评估每个:Mul (Word "x") (Word "y")
有意义吗?如果不是,你String
会返回什么?
我建议两件事:
首先,定义一个simplify
函数,负责将AST
简化为更简单的东西。它会在 的 情况下处理诸如数值算术之类的Plus (Num ...) (Num ...)
事情,但保持Word x
or之类的事情Plus (Word x) (Num y)
不变。
simplify :: AST -> AST
simplify (Num x) = Num x -- Easy case done for you; no simplification necessary
simplify (Word x) = ...
-- Hint: in each of the following, you need to recursively simplify the operands.
-- Once you do that, you can either simplify further, or return a new
-- node to be evaluated.
simplify (Plus x y) = ...
simplify (Minus x y) = ...
simplify (Mul x y) = ...
其次, defineeval :: AST -> Either String String
将首先simplify
在其参数上使用,然后AST
在可行的情况下将s逐个转换,Strings
并在不可行的情况下返回适当的错误消息。
eval :: AST -> Either String String
eval x = eval' (simplify x)
where eval' (Word x) = Right x -- Easy case done for you
eval' (Num x) = ...
-- simplify will have reduced all the Num + Num, Num - Num, and
-- Num * Num nodes to single Num nodes already.
eval' (Plus (Word x) (Word y)) = x ++ y -- Other easy case done above
eval' (Plus x y) = ...
eval' (Minus (Word x) (Word y)) = ...
eval' (Minus x y) = ...
eval' (Mul (Word x) (Word y)) = ...
eval' (Mul x y) = ...
请注意,您可以想象在eval'
or中定义一些组合simplify
,例如
simplify (Plus (Word x) (Word y)) == Word $ x ++ y
将更复杂(并且可能不可能)的情况留给eval
.
推荐阅读
- microsoft-graph-api - 频道 lastModifiedDateTime 完全错误
- reactjs - 元素类型无效:需要一个字符串(用于内置组件)或 webpack 构建后的类/函数
- laravel - Laravel 通过不同的方法发送相同的通知
- string - 如何将字节从 rust 字符串中移出
- python - 从 mongo-db 中的最后一条记录中获取一列值
- flutter - 有什么方法可以在颤振中使用 zefyrEditor 中的验证属性和 onChanged 属性?
- r - 如何计算R中某段时间的最大平均值?
- c# - 用于检查多个纬度和经度值的正则表达式模式
- networking - 访问 google.com 时出现 ERR_CERT_COMMON_NAME_INVALID
- python - 无法使用超级用户帐户登录到管理站点,该帐户是使用控制台创建的 // Django