summaryrefslogtreecommitdiff
path: root/test/KB/terms.ml
blob: dba7000646464a849fc623b4dfa2d911bb235d81 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
(***********************************************************************)
(*                                                                     *)
(*                           Objective Caml                            *)
(*                                                                     *)
(*            Xavier Leroy, projet Cristal, INRIA Rocquencourt         *)
(*                                                                     *)
(*  Copyright 1996 Institut National de Recherche en Informatique et   *)
(*  en Automatique.  All rights reserved.  This file is distributed    *)
(*  under the terms of the Q Public License version 1.0.               *)
(*                                                                     *)
(***********************************************************************)

(* $Id$ *)

(****************** 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