При написании функционального кода для представления и оценки выражений типичным шаблоном является определение типа выражения как различимого объединения (как вы это сделали!), А затем запись функции, которая принимает выражение и возвращает результат. Ваши логические выражения будут оцениваться как логические, поэтому вам нужна функция:
evalLogic : Expr -> bool
В функции вам нужно написать регистр для каждого возможного выражения. Ваш пример обрабатывает False
и True
, а код Bluepixy показывает все остальное. Общая идея состоит в том, что функция может рекурсивно оценивать все подвыражения - если у вас есть And(e1, e2)
, то вы можете вычислить e1
и e2
до двух логических значений и затем объединить их (используя &&
).
Ваша функция 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
выглядит так:
let rec evalLogic e =
// pattern matching
| Binary(e1, e2, op) -> op (evalLogic e1) (evalLogic e2)