Raw text file


(* Section 3 *)

let rec list_remove_all e = function
  | [] -> []
  | e' :: q ->
      if e = e' then list_remove_all e q
      else e' :: list_remove_all e q

(****************************************************)

type var
type typeconstr


(* Solution using polymorphic variants *)
module VP = struct

type monotype = [ `Var of var | `Constr of typeconstr * monotype list ]

type ('a, 'b) bound = [ `Bound of (var * 'a) * 'b ]
type bot = [ `Bottom ]

type polytype = [ monotype | bot | (polytype, polytype) bound ]


(* Free type variables *)
let rec ftv_monotype : monotype -> _ = function
  | `Var v -> [v]
  | `Constr (_, l) -> List.concat (List.map ftv_monotype l)
and ftv_polytype : polytype -> _ = function
  | #monotype as m -> ftv_monotype m
  | `Bottom -> []
  | `Bound ((v, t), t') ->
      ftv_polytype t @ (list_remove_all v (ftv_polytype t'))


(* Substitution of a variable by a monotype *)
let rec expand_mono_in_mono (v, m) = function
  | `Var v' -> if v = v' then m else `Var v'
  | `Constr (c, l) -> `Constr (c, List.map (expand_mono_in_mono (v, m)) l)
and expand_mono_in_poly (v, m) : polytype -> _ = function
  | #monotype as m' -> (expand_mono_in_mono (v, m) m' :> polytype)
  | `Bottom -> `Bottom
  | `Bound ((v', t), t') ->
      `Bound ((v', expand_mono_in_poly (v, m) t),
              if v = v' then t' else expand_mono_in_poly (v, m) t')


(* Types for the normal form *)
type constr = [ `Constr of typeconstr * monotype list ]

type nf_polytype = [ monotype | bot | (bot_poly, constr_poly) bound ]
and bot_poly  =    [            bot | (bot_poly, constr_poly) bound ]
and constr_poly =  [ constr   |       (bot_poly, constr_poly) bound ]


let rec nf : polytype -> nf_polytype = function
  | #bot | #monotype as t -> t
  | `Bound ((v, t), t') ->
      match nf t with
        | #monotype as m' -> nf (expand_mono_in_poly (v, m') t') (* Eq-Mono*)
        | #bot_poly as t ->
            match nf t' with
              | `Var v' ->
                  if v = v' then t (* Eq-Var *)
                  else `Var v' (* Eq-Free *)
              | #bot -> `Bottom (* Eq-Free *)
              | #constr_poly as t' ->
                  let ftv = ftv_polytype (t' : constr_poly :> polytype) in
                  if List.mem v ftv then `Bound ((v, t), t')
                  else t' (* Eq-Free *)
end


(* Solution using standard inductive *)
module IND = struct

type monotype = Var of var | Constr of constr
and constr = typeconstr * monotype list

type ('a, 'b) bound = (var * 'a) * 'b

type polytype =
    Mono of monotype  | Bot  | Bound of  (polytype, polytype)    bound
type nf_poly =
    Mono1 of monotype | Bot1 | Bound1 of (bot_poly, constr_poly) bound
and constr_poly =
    Constr3 of constr |        Bound3 of (bot_poly, constr_poly) bound
and bot_poly =          Bot2 | Bound2 of (bot_poly, constr_poly) bound


(* Substitution of variables by monotypes *)
let rec expand_mono_in_mono (v, m) = function
  | Var v' -> if v = v' then m else Var v'
  | Constr (c, l) -> Constr (c, List.map (expand_mono_in_mono (v, m)) l)

let rec expand_mono_in_poly (v, m) = function
  | Mono m' -> Mono (expand_mono_in_mono (v, m) m')
  | Bot -> Bot
  | Bound ((v', t), t') ->
      Bound ((v', expand_mono_in_poly (v, m) t),
             if v = v' then t' else expand_mono_in_poly (v, m) t')


(* Free type variables on bounds, monotypes, polytypes dans subsets
   of polytypes. We try to reuse as much code as possible *)
let ftv_bound ((v, t), t' : (_, _) bound) f1 f2 =
  f1 t @ (list_remove_all v (f2 t'))

let rec ftv_monotype = function
  | Var v -> [v]
  | Constr (_, l) -> ftv_list_monotype l
and ftv_list_monotype l = List.concat (List.map ftv_monotype l)
(* Not used in the solution
and ftv_polytype = function
  | Mono m -> ftv_monotype m
  | Bot -> []
  | Bound b -> ftv_bound b ftv_polytype ftv_polytype
*)

let rec ftv_poly = function
  | Bot2 -> []
  | Bound2 b -> ftv_bound' b
and ftv_constr = function
  | Constr3 (_, l) -> ftv_list_monotype l
  | Bound3 b -> ftv_bound' b
and ftv_bound' b = ftv_bound b ftv_poly ftv_constr


(* Projection of constr_poly and bot_poly into nf_poly. In constant time *)
let bot_to_nf = function
  | Bot2 -> Bot1
  | Bound2 b -> Bound1 b
let constr_to_nf = function
  | Constr3 b -> Mono1 (Constr b)
  | Bound3 b -> Bound1 b


let rec nf = function
  | Mono m -> Mono1 m
  | Bot -> Bot1
  | Bound ((v, t), t') ->
      let aux1 nft =
        let aux2 nft' =
          let ftv = ftv_constr nft' in
          if List.mem v ftv then Bound1 ((v, nft), nft')
          else (constr_to_nf nft')
        in
        match nf t' with
          | Bot1 -> Bot1
          | Mono1 (Var v') ->
              if v = v' then (bot_to_nf nft)
              else (Mono1 (Var v'))
          | Mono1 (Constr b) -> aux2 (Constr3 b)
          | Bound1 b' -> aux2 (Bound3 b')
      in
      match nf t with
        | Mono1 m -> nf (expand_mono_in_poly (v, m) t')
        | Bound1 b -> aux1 (Bound2 b)
        | Bot1 -> aux1 Bot2


end

This document was generated using caml2html