尝试习惯F#我尝试了一些小例子,我的下一步是为逻辑计算/评估编写一些函数,现在我有了这个结构
type Expr =
| True
| False
| Not of Expr
| And of Expr * Expr
并且我应该明白我想要实现的目标:能够封装不同的函数,如Not
和And
,以便在And(And(True, Not(False)), True)
之类的计算中使用,但目前我还没有理解(这是我第一次打算这样的“复杂”功能代码)如何使用这个结构并编写正确的方法,例如我可以写评估
let evalLogic (expr : Expr) : bool =
match expr with
| True -> true
| False -> false
| _ -> false (* eval the expression which is not "atomic" *)
然后作为方法
let And (left : Expr , right : Expr ) : Expr =
let value = evalLogic(left) && evalLogic(right)
match value with
| true -> True
| false -> False
然而我知道这是垃圾,而不是正确的实现方式!你能给我一个如何实现理想行为的提示并描述如何扩展它吗?
答案 0 :(得分:6)
在编写表示和计算表达式的函数代码时,典型的模式是将表达式的类型定义为区别联合(就像你所做的那样!)然后编写一个接受表达式并返回结果的函数。您的逻辑表达式将计算为布尔值,因此您需要一个函数:
evalLogic : Expr -> bool
在函数中,您需要为每个可能的表达式编写一个案例。您的示例处理False
和True
,Bluepixy的代码显示其余部分。一般的想法是函数可以递归地评估所有子表达式 - 如果你有And(e1, e2)
,那么你可以将e1
和e2
评估为两个布尔值,然后将它们组合起来(使用{ {1}})。
您不需要&&
功能,因为整个评估都是在And
功能中完成的。这是在功能样式中执行操作的典型方式(因为表达式类型不会经常更改)。但是,您还可以使用以下方法支持更多二进制操作:
evalLogic
这里的想法是表达式是常量或某些二元或一元逻辑运算符的应用程序。例如,要表示type Expr =
| Constant of bool
| Unary of Expr * (bool -> bool)
| Binary of Expr * Expr * (bool -> bool -> bool)
,您可以写:
true && not false
现在表达式树还带有应该使用的函数,因此评估只需要调用函数(并且您可以轻松地使用所有标准逻辑运算符)。例如,Binary(Constant(true), Unary(Constant(false), not), (&&))
的大小写如下:
Binary
答案 1 :(得分:3)
let rec evalLogic (expr : Expr) : bool =
match expr with
| True -> true
| False -> false
| Not (exp ) -> not (evalLogic exp)
| And (expL, expR) -> evalLogic expL && evalLogic expR
<强>样本强>
> evalLogic <| And(And(True, Not(False)), True);;
val it : bool = true
答案 2 :(得分:2)
您的问题是“如何为evalLogic
和Not
延长And
?”
如果是这样,那么你需要在let-expression中扩展模式匹配以匹配其他两个构造函数:
let evalLogic (expr : Expr) : bool =
match expr with
| True -> true
| False -> false
| Not (myexpr) -> ... (* match constructor `Not`, bind the expression to `myexpr`)
| And (lefte, righte) -> ...
然后你可以用一些F#代码填写右侧。
Here's关于F#中模式匹配的一些信息。