F#类型和基本计算的动态评估

时间:2011-10-29 12:49:48

标签: f# functional-programming logic expression expression-trees

尝试习惯F#我尝试了一些小例子,我的下一步是为逻辑计算/评估编写一些函数,现在我有了这个结构

type Expr =
    | True
    | False
    | Not of Expr
    | And of Expr * Expr

并且我应该明白我想要实现的目标:能够封装不同的函数,如NotAnd,以便在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

然而我知道这是垃圾,而不是正确的实现方式!你能给我一个如何实现理想行为的提示并描述如何扩展它吗?

3 个答案:

答案 0 :(得分:6)

在编写表示和计算表达式的函数代码时,典型的模式是将表达式的类型定义为区别联合(就像你所做的那样!)然后编写一个接受表达式并返回结果的函数。您的逻辑表达式将计算为布尔值,因此您需要一个函数:

evalLogic : Expr -> bool

在函数中,您需要为每个可能的表达式编写一个案例。您的示例处理FalseTrue,Bluepixy的代码显示其余部分。一般的想法是函数可以递归地评估所有子表达式 - 如果你有And(e1, e2),那么你可以将e1e2评估为两个布尔值,然后将它们组合起来(使用{ {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)

您的问题是“如何为evalLogicNot延长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#中模式匹配的一些信息。