В общем, хорошей практикой является делиться своими попытками задавать вопросы по SO. Люди обычно не дадут вам полного решения ваших проблем - просто ответят, когда у вас есть конкретный вопрос, или намеки, как подойти к проблеме.
Итак, я поделюсь некоторыми советами об общем подходе, но это не полное решение .
Во-первых, вы должны каким-то образом представлять свой АСТ. В F # вы можете сделать это, используя дискриминационные союзы. Поддерживаются следующие переменные, значения и приложения функций:
type Expr =
| Function of string * Expr list
| Variable of string
| Value of int
Unification - это функция, которая принимает список выражений для объединения типа (Expr * Expr) list
и возвращает присваивания переменным (присваивание выражения Expr
имени переменной string
):
let rec unify exprs =
match exprs with
// Unify two variables - if they are equal, we continue unifying
// the rest of the constraints, otherwise the algorithm fails
| (Variable s1, Variable s2)::remaining ->
if s1 = s2 then unify remaining
else failwith "cannot unify variables"
// Unify variable with some other expression - unify the remaining
// constraints and add new assignment to the result
| (Variable s, expr)::remaining
| (expr, Variable s)::remaining ->
let rest = unify remaining
// (s, expr) is a tuple meaning that we assign 'expr' to variable 's'
(s, expr)::rest
// TODO: Handle remaining cases here!
| _ -> failwith "cannot unify..."
Есть несколько случаев, которые вам нужно добавить. Самое главное, объединение Function
с Function
означает, что вам нужно проверить, совпадают ли имена функций (в противном случае произойдет сбой), а затем добавить все выражения аргумента в качестве новых ограничений в список remaining
...