我正在尝试为可以在F#中添加或乘法的表达式树构建一个解释器,但是我遇到了一些麻烦。我也试图使用选项类型,以便如果变量不在表达式中,则解释器返回None。
这是我给出的代码。
type Exptree =
| Const of int
| Var of string
| Add of Exptree * Exptree
| Mul of Exptree * Exptree
type Bindings = (string * int) list
let rec eval(exp : Exptree, env:Bindings) =
match exp with
|
我对与exp匹配的内容感到困惑,因为有很多选项。我的想法是看看Add和Mul,并尝试在每个递归步骤中将其删除,直到我得到一个整数,但是我完全迷失了。
我能做点什么吗?
match exp with
| Some(Add) -> int + int?
| Some(Mul) -> int * int?
答案 0 :(得分:6)
您的Exptree类型有四种可能的构造函数:Const,Var,Add和Mul。所以,你的匹配将是那些:
match exp with
| Const c ->
| Var s ->
| Add (e1,e2) ->
| Mul (e1,e2) ->
对于每种情况,您都会执行相应的操作(在环境中添加,乘法,查找变量,返回常量)。在add和mul的情况下,你会解释子表达式(e1和e2)上eval的递归调用的结果,看看值是None还是Some(s),并相应地对它进行操作。
答案 1 :(得分:4)
因此,scrwtp是正确的,Map<string, int>
对您的绑定集更有意义,因为您可以在O(log n)时间内执行查找,而不是在list
的O(n)时间内执行查找。
eval
功能的第一部分很简单:
Some
。Some
。如果它们不存在,我们返回None
。我们可以使用Map.tryFind
来执行此操作。我们可以这样做:
let rec eval bindings tree =
match tree with
|Const i -> Some i
|Var varName -> Map.tryFind varName bindings
执行加法和乘法需要更多考虑。为了抽象组合两个子树,有意义的是定义一个函数,该函数将两个选项作为参数,并允许您将两个结果的函数应用于Some value
。这称为lift2
函数,我们可以为Option
:
/// Combines two option values using a supplied function
let lift2 f opt1 opt2 =
match (opt1, opt2) with
|Some val1, Some val2 -> Some <| f val1 val2
|_ -> None
有关lift
系列函数的更多信息,请参阅此精彩教程:http://fsharpforfunandprofit.com/posts/elevated-world/#lift
现在我们可以通过调用此函数来扩展我们的eval
函数以用于加法和乘法。
/// Evaluates the result of an expression tree
let rec eval bindings tree =
match tree with
|Const i -> Some i // Const always returns some value
|Var varName -> Map.tryFind varName bindings // Returns some value if it exists in the binding table
|Add (tree1, tree2) ->
lift2 (+) (eval bindings tree1) (eval bindings tree2) // add expressions if both expressions return Some val
|Mul (tree1, tree2) ->
lift2 (*) (eval bindings tree1) (eval bindings tree2) // multiply expressions if both expressions return Some val
现在,添加案例使用lift2
函数来说明,如果两个子表达式都计算为实数值,则将结果一起添加,否则返回None
。
乘法情况遵循完全相同的逻辑,我们刚刚交换了运算符。
快速搁置:正如GuyCoder所指出的,构建绑定表的一种便捷方法是使用语法:
let bindings = Map.ofList [("a",1); ("b",2); ("c",3)]