ocaml/test/KB/terms.ml

124 lines
3.2 KiB
OCaml

(****************** Term manipulations *****************)
type term =
Var of int
| Term of string * term list
let rec union l1 l2 =
match l1 with
[] -> l2
| a::r -> if List.mem a l2 then union r l2 else a :: union r l2
let rec vars = function
Var n -> [n]
| Term(_,l) -> vars_of_list l
and vars_of_list = function
[] -> []
| t::r -> union (vars t) (vars_of_list r)
let rec substitute subst = function
Term(oper,sons) -> Term(oper, List.map (substitute subst) sons)
| Var(n) as t -> try List.assoc n subst with Not_found -> t
(* Term replacement: replace M u N is M[u<-N]. *)
let rec replace m u n =
match (u, m) with
[], _ -> n
| i::u, Term(oper, sons) -> Term(oper, replace_nth i sons u n)
| _ -> failwith "replace"
and replace_nth i sons u n =
match sons with
s::r -> if i = 1
then replace s u n :: r
else s :: replace_nth (i-1) r u n
| [] -> failwith "replace_nth"
(* Term matching. *)
let matching term1 term2 =
let rec match_rec subst t1 t2 =
match (t1, t2) with
Var v, _ ->
if List.mem_assoc v subst then
if t2 = List.assoc v subst then subst else failwith "matching"
else
(v, t2) :: subst
| Term(op1,sons1), Term(op2,sons2) ->
if op1 = op2
then List.fold_left2 match_rec subst sons1 sons2
else failwith "matching"
| _ -> failwith "matching" in
match_rec [] term1 term2
(* A naive unification algorithm. *)
let compsubst subst1 subst2 =
(List.map (fun (v,t) -> (v, substitute subst1 t)) subst2) @ subst1
let rec occurs n = function
Var m -> m = n
| Term(_,sons) -> List.exists (occurs n) sons
let rec unify term1 term2 =
match (term1, term2) with
Var n1, _ ->
if term1 = term2 then []
else if occurs n1 term2 then failwith "unify"
else [n1, term2]
| term1, Var n2 ->
if occurs n2 term1 then failwith "unify"
else [n2, term1]
| Term(op1,sons1), Term(op2,sons2) ->
if op1 = op2 then
List.fold_left2 (fun s t1 t2 -> compsubst (unify (substitute s t1)
(substitute s t2)) s)
[] sons1 sons2
else failwith "unify"
(* We need to print terms with variables independently from input terms
obtained by parsing. We give arbitrary names v1,v2,... to their variables.
*)
let infixes = ["+";"*"]
let rec pretty_term = function
Var n ->
print_string "v"; print_int n
| Term (oper,sons) ->
if List.mem oper infixes then begin
match sons with
[s1;s2] ->
pretty_close s1; print_string oper; pretty_close s2
| _ ->
failwith "pretty_term : infix arity <> 2"
end else begin
print_string oper;
match sons with
[] -> ()
| t::lt -> print_string "(";
pretty_term t;
List.iter (fun t -> print_string ","; pretty_term t) lt;
print_string ")"
end
and pretty_close = function
Term(oper, _) as m ->
if List.mem oper infixes then begin
print_string "("; pretty_term m; print_string ")"
end else
pretty_term m
| m ->
pretty_term m