Trying to get used to F# I tried small examples and my next step is to write a few functions for logical computations/evaluations and for now I have this structure
type Expr =
| True
| False
| Not of Expr
| And of Expr * Expr
and it should be obvious what I want to achieve: to be able to encapsulate different functions like Not and And to be used in one computation like And(And(True, Not(False)), True) but currently I do not understand (this is my first time wrinting such “complex” functional code) how to use this struct and write the proper methods as for example i can write for evaluation
let evalLogic (expr : Expr) : bool =
match expr with
| True -> true
| False -> false
| _ -> false (* eval the expression which is not "atomic" *)
and then as a method
let And (left : Expr , right : Expr ) : Expr =
let value = evalLogic(left) && evalLogic(right)
match value with
| true -> True
| false -> False
however I know that this is crap and not the correct way of implementing this! Can you give me a hint how to achieve the desired behavior and describe how to extend this?
When writing functional code to represent and evaluate expressions, the typical pattern is to define the type of expression as a discriminated union (just like you did!) and then write a function that takes the expression and returns the result. Your logical expressions will evaluate to boolean, so you need a function:
In the function, you need to write a case for every possible expression. Your sample handles
FalseandTrueand the code by Bluepixy shows the rest. The general idea is that the function can recursively evaluate all sub-expressions – if you haveAnd(e1, e2), then you can evaluatee1ande2to two boolean values and then combine them (using&&).Your
Andfunction is not needed, because the whole evaluation is all done in theevalLogicfunction. This is a typical way of doing things in the functional style (because the expression type is not expected to change frequently). Howeever, you could also support more binary operations using:Here, the idea is that an expression is either a constant or an application of some binary or unary logical operator. For example, to represent
true && not false, you could write:Now the expression tree also carries the function that should be used, so the evaluation just needs to call the function (and you can use all standard logical operators easily). For example, the case for
Binarylooks like this: