(**TD06**)
open T
open
 Type

exception
 Error of string

type
 eqs = (Type.t * Type.tlist
type
 subst = (int * Type.tlist

(***********************)
(* Quelques afficheurs *)
(***********************)


open  Printf

let
 print_eq chan (t1,t2) =
  fprintf chan "%a = %a" Type.print t1 Type.print t2

let
 print_eqs chan eqs =
  List.iter
    (fun eq -> fprintf chan "%a\n" print_eq eq)
    eqs ;
  flush chan

let
 print_subst chan s =
  print_eqs chan
    (List.map (fun (n,t) -> Tvar n,ts) ;
  flush chan


(***************************************)
(* Algorithme d'unification de Robison *)
(***************************************)

(* occur_check, comme le nom l'indique *)

let rec occur_check n t = match t with
Nat -> ()
Arrow (t1,t2) -> occur_check n t1 ; occur_check n t2
Tvar m -> if n=m then raise (Error "Occur")

(** Appliquer une substitution à une variable *)
let subst s x = try List.assoc x s with Not_found -> Tvar x

(** 'subst_type s t' applique la substitution 's' au type 't' *)
let rec subst_type s t = match t with
  | Nat -> Nat
  | Tvar x -> subst s x
  | Arrow (t1t2) ->
      Arrow (subst_type s t1subst_type s t2)

(** Appliquer une substitution à un ensemble d'équations *)
let rec subst_eqs s eqs =
  List.map (fun (t1,t2) -> subst_type s t1subst_type s t2eqs

(** Et à une substitution *)
let rec subst_subst s0 s1 =
  List.map (fun (x,t) -> xsubst_type s0 ts1


(*****************************************)
(* Algorithme de Robinson proprement dit *)
(*****************************************)

(*
   Les arguments de unif :
  - eqs est la liste des équations non-examinées.
  - r est la liste des équations examinées (sous forme de substitution)
*)

let rec unif eqs r = match eqs with
| [] -> r
| (t1,t2)::eqs -> unif_rec t1 t2 eqs r

(* Traiter l'équation t1=t2, il reste eqs à examiner,
   r sont déjà examinées *)

and unif_rec t1 t2 eqs r = match t1,t2 with
(* Chouette or-pat *)
| (Nat,Arrow (_,_))|(Arrow (_,_),Nat) -> raise (Error "Nat against A->B")
Arrow (t1,t2),Arrow (t3,t4) ->
    unif_rec t1 t3 ((t2,t4)::eqsr
Nat,Nat -> unif eqs r
(* Noter la garde 'when' *)
Tvar nTvar m when n=m -> unif eqs r
(* Encore un or-pat, encore plus chouette *)
| (Tvar n,t)|(t,Tvar n) ->
    occur_check n t ;
    (* Tout est là : bien prendre garde de remplacer n par t PARTOUT *)
    unif (subst_eqs [n,teqs) ((n,t)::subst_subst [n,tr)

(* 'verbose' est 'true' si on a donné l'option "-v" sur la ligne de commande *)
let verbose = List.mem "-v" (Array.to_list Sys.argv)

let mgu eqs =
  if verbose then begin
    prerr_endline "*** EQS ***" ;
    print_eqs stderr eqs
  end ;
  let s = unif eqs [] in
  if verbose then begin
    prerr_endline "*** SUBST ***" ;
    print_subst stderr s ; flush stderr
  end ;
  s

(* Un truc simple pour avoir des variables « fraîches » *)
let fresh_var =
  let c = ref 0 in
  fun () -> let r = !c in incr c ; r

let
 mgu_incr t1 t2 s =
  if verbose then begin
    prerr_endline "*** EQ ***" ;
    print_eq stderr (t1,t2) ;
    eprintf "\n + SUBST\n" ;
    print_subst stderr s ;
    flush stderr
  end ;
  let s = unif_rec (subst_type s t1) (subst_type s t2) [] s in
  if verbose then begin
    prerr_endline "*** RESULT ***" ;
    print_subst stderr s ;
    prerr_endline "** END **"
  end ;
  s

(**END**)

This document was translated from LATEX by HEVEA.