ocaml/test/Moretest/recmod.ml

512 lines
12 KiB
OCaml

(* Tests for recursive modules *)
let test number result expected =
if result = expected
then Printf.printf "Test %d passed.\n" number
else Printf.printf "Test %d FAILED.\n" number;
flush stdout
(* Tree of sets *)
module rec A
: sig
type t = Leaf of int | Node of ASet.t
val compare: t -> t -> int
end
= struct
type t = Leaf of int | Node of ASet.t
let compare x y =
match (x,y) with
(Leaf i, Leaf j) -> Pervasives.compare i j
| (Leaf i, Node t) -> -1
| (Node s, Leaf j) -> 1
| (Node s, Node t) -> ASet.compare s t
end
and ASet : Set.S with type elt = A.t = Set.Make(A)
;;
let _ =
let x = A.Node (ASet.add (A.Leaf 3) (ASet.singleton (A.Leaf 2))) in
let y = A.Node (ASet.add (A.Leaf 1) (ASet.singleton x)) in
test 10 (A.compare x x) 0;
test 11 (A.compare x (A.Leaf 3)) 1;
test 12 (A.compare (A.Leaf 0) x) (-1);
test 13 (A.compare y y) 0;
test 14 (A.compare x y) 1
;;
(* Simple value recursion *)
module rec Fib
: sig val f : int -> int end
= struct let f x = if x < 2 then 1 else Fib.f(x-1) + Fib.f(x-2) end
;;
let _ =
test 20 (Fib.f 10) 89
;;
(* Update function by infix *)
module rec Fib2
: sig val f : int -> int end
= struct let rec g x = Fib2.f(x-1) + Fib2.f(x-2)
and f x = if x < 2 then 1 else g x
end
;;
let _ =
test 21 (Fib2.f 10) 89
;;
(* Early application *)
let _ =
let res =
try
let module A =
struct
module rec Bad
: sig val f : int -> int end
= struct let f = let y = Bad.f 5 in fun x -> x+y end
end in
false
with Undefined_recursive_module _ ->
true in
test 30 res true
;;
(* Early strict evaluation *)
(*
module rec Cyclic
: sig val x : int end
= struct let x = Cyclic.x + 1 end
;;
*)
(* Reordering of evaluation based on dependencies *)
module rec After
: sig val x : int end
= struct let x = Before.x + 1 end
and Before
: sig val x : int end
= struct let x = 3 end
;;
let _ =
test 40 After.x 4
;;
(* Type identity between A.t and t within A's definition *)
module rec Strengthen
: sig type t val f : t -> t end
= struct
type t = A | B
let _ = (A : Strengthen.t)
let f x = if true then A else Strengthen.f B
end
;;
module rec Strengthen2
: sig type t
val f : t -> t
module M : sig type u end
module R : sig type v end
end
= struct
type t = A | B
let _ = (A : Strengthen2.t)
let f x = if true then A else Strengthen2.f B
module M =
struct
type u = C
let _ = (C: Strengthen2.M.u)
end
module rec R : sig type v = Strengthen2.R.v end =
struct
type v = D
let _ = (D : R.v)
let _ = (D : Strengthen2.R.v)
end
end
;;
(* Polymorphic recursion *)
module rec PolyRec
: sig
type 'a t = Leaf of 'a | Node of 'a list t * 'a list t
val depth: 'a t -> int
end
= struct
type 'a t = Leaf of 'a | Node of 'a list t * 'a list t
let x = (PolyRec.Leaf 1 : int t)
let depth = function
Leaf x -> 0
| Node(l,r) -> 1 + max (PolyRec.depth l) (PolyRec.depth r)
end
;;
(* Wrong LHS signatures (PR#4336) *)
(*
module type ASig = sig type a val a:a val print:a -> unit end
module type BSig = sig type b val b:b val print:b -> unit end
module A = struct type a = int let a = 0 let print = print_int end
module B = struct type b = float let b = 0.0 let print = print_float end
module MakeA (Empty:sig end) : ASig = A
module MakeB (Empty:sig end) : BSig = B
module
rec NewA : ASig = MakeA (struct end)
and NewB : BSig with type b = NewA.a = MakeB (struct end);;
*)
(* Expressions and bindings *)
module StringSet = Set.Make(String);;
module rec Expr
: sig
type t =
Var of string
| Const of int
| Add of t * t
| Binding of Binding.t * t
val make_let: string -> t -> t -> t
val fv: t -> StringSet.t
val simpl: t -> t
end
= struct
type t =
Var of string
| Const of int
| Add of t * t
| Binding of Binding.t * t
let make_let id e1 e2 = Binding([id, e1], e2)
let rec fv = function
Var s -> StringSet.singleton s
| Const n -> StringSet.empty
| Add(t1,t2) -> StringSet.union (fv t1) (fv t2)
| Binding(b,t) ->
StringSet.union (Binding.fv b)
(StringSet.diff (fv t) (Binding.bv b))
let rec simpl = function
Var s -> Var s
| Const n -> Const n
| Add(Const i, Const j) -> Const (i+j)
| Add(Const 0, t) -> simpl t
| Add(t, Const 0) -> simpl t
| Add(t1,t2) -> Add(simpl t1, simpl t2)
| Binding(b, t) -> Binding(Binding.simpl b, simpl t)
end
and Binding
: sig
type t = (string * Expr.t) list
val fv: t -> StringSet.t
val bv: t -> StringSet.t
val simpl: t -> t
end
= struct
type t = (string * Expr.t) list
let fv b =
List.fold_left (fun v (id,e) -> StringSet.union v (Expr.fv e))
StringSet.empty b
let bv b =
List.fold_left (fun v (id,e) -> StringSet.add id v)
StringSet.empty b
let simpl b =
List.map (fun (id,e) -> (id, Expr.simpl e)) b
end
;;
let _ =
let e = Expr.make_let "x" (Expr.Add (Expr.Var "y", Expr.Const 0))
(Expr.Var "x") in
let e' = Expr.make_let "x" (Expr.Var "y") (Expr.Var "x") in
test 50 (StringSet.elements (Expr.fv e)) ["y"];
test 51 (Expr.simpl e) e'
;;
(* Okasaki's bootstrapping *)
module type ORDERED =
sig
type t
val eq: t -> t -> bool
val lt: t -> t -> bool
val leq: t -> t -> bool
end
module type HEAP =
sig
module Elem: ORDERED
type heap
val empty: heap
val isEmpty: heap -> bool
val insert: Elem.t -> heap -> heap
val merge: heap -> heap -> heap
val findMin: heap -> Elem.t
val deleteMin: heap -> heap
end
module Bootstrap (MakeH: functor (Element:ORDERED) ->
HEAP with module Elem = Element)
(Element: ORDERED) : HEAP with module Elem = Element =
struct
module Elem = Element
module rec BE
: sig type t = E | H of Elem.t * PrimH.heap
val eq: t -> t -> bool
val lt: t -> t -> bool
val leq: t -> t -> bool
end
= struct
type t = E | H of Elem.t * PrimH.heap
let leq t1 t2 =
match t1, t2 with
| (H(x, _)), (H(y, _)) -> Elem.leq x y
| H _, E -> false
| E, H _ -> true
| E, E -> true
let eq t1 t2 =
match t1, t2 with
| (H(x, _)), (H(y, _)) -> Elem.eq x y
| H _, E -> false
| E, H _ -> false
| E, E -> true
let lt t1 t2 =
match t1, t2 with
| (H(x, _)), (H(y, _)) -> Elem.lt x y
| H _, E -> false
| E, H _ -> true
| E, E -> false
end
and PrimH
: HEAP with type Elem.t = BE.t
= MakeH(BE)
type heap = BE.t
let empty = BE.E
let isEmpty = function BE.E -> true | _ -> false
let rec merge x y =
match (x,y) with
(BE.E, _) -> y
| (_, BE.E) -> x
| (BE.H(e1,p1) as h1), (BE.H(e2,p2) as h2) ->
if Elem.leq e1 e2
then BE.H(e1, PrimH.insert h2 p1)
else BE.H(e2, PrimH.insert h1 p2)
let insert x h =
merge (BE.H(x, PrimH.empty)) h
let findMin = function
BE.E -> raise Not_found
| BE.H(x, _) -> x
let deleteMin = function
BE.E -> raise Not_found
| BE.H(x, p) ->
if PrimH.isEmpty p then BE.E else begin
match PrimH.findMin p with
| (BE.H(y, p1)) ->
let p2 = PrimH.deleteMin p in
BE.H(y, PrimH.merge p1 p2)
| BE.E -> assert false
end
end
;;
module LeftistHeap(Element: ORDERED): HEAP with module Elem = Element =
struct
module Elem = Element
type heap = E | T of int * Elem.t * heap * heap
let rank = function E -> 0 | T(r,_,_,_) -> r
let make x a b =
if rank a >= rank b
then T(rank b + 1, x, a, b)
else T(rank a + 1, x, b, a)
let empty = E
let isEmpty = function E -> true | _ -> false
let rec merge h1 h2 =
match (h1, h2) with
(_, E) -> h1
| (E, _) -> h2
| (T(_, x1, a1, b1), T(_, x2, a2, b2)) ->
if Elem.leq x1 x2
then make x1 a1 (merge b1 h2)
else make x2 a2 (merge h1 b2)
let insert x h = merge (T(1, x, E, E)) h
let findMin = function
E -> raise Not_found
| T(_, x, _, _) -> x
let deleteMin = function
E -> raise Not_found
| T(_, x, a, b) -> merge a b
end
;;
module Ints =
struct
type t = int
let eq = (=)
let lt = (<)
let leq = (<=)
end
;;
module C = Bootstrap(LeftistHeap)(Ints);;
let _ =
let h = List.fold_right C.insert [6;4;8;7;3;1] C.empty in
test 60 (C.findMin h) 1;
test 61 (C.findMin (C.deleteMin h)) 3;
test 62 (C.findMin (C.deleteMin (C.deleteMin h))) 4
;;
(* Classes *)
module rec Class1
: sig
class c : object method m : int -> int end
end
= struct
class c =
object
method m x = if x <= 0 then x else (new Class2.d)#m x
end
end
and Class2
: sig
class d : object method m : int -> int end
end
= struct
class d =
object(self)
inherit Class1.c as super
method m (x:int) = super#m 0
end
end
;;
let _ =
test 70 ((new Class1.c)#m 7) 0
;;
let _ =
try
let module A = struct
module rec BadClass1
: sig
class c : object method m : int end
end
= struct
class c = object method m = 123 end
end
and BadClass2
: sig
val x: int
end
= struct
let x = (new BadClass1.c)#m
end
end in
test 71 true false
with Undefined_recursive_module _ ->
test 71 true true
;;
(* Coercions *)
module rec Coerce1
: sig
val g: int -> int
val f: int -> int
end
= struct
module A = (Coerce1: sig val f: int -> int end)
let g x = x
let f x = if x <= 0 then 1 else A.f (x-1) * x
end
;;
let _ =
test 80 (Coerce1.f 10) 3628800
;;
module CoerceF(S: sig end) = struct
let f1 () = 1
let f2 () = 2
let f3 () = 3
let f4 () = 4
let f5 () = 5
end
module rec Coerce2: sig val f1: unit -> int end = CoerceF(Coerce3)
and Coerce3: sig end = struct end
;;
let _ =
test 81 (Coerce2.f1 ()) 1
;;
module Coerce4(A : sig val f : int -> int end) = struct
let x = 0
let at a = A.f a
end
module rec Coerce5
: sig val blabla: int -> int val f: int -> int end
= struct let blabla x = 0 let f x = 5 end
and Coerce6
: sig val at: int -> int end
= Coerce4(Coerce5)
let _ =
test 82 (Coerce6.at 100) 5
;;
(* Miscellaneous bug reports *)
module rec F
: sig type t = X of int | Y of int
val f: t -> bool
end
= struct
type t = X of int | Y of int
let f = function
| X _ -> false
| _ -> true
end;;
let _ =
test 100 (F.f (F.X 1)) false;
test 101 (F.f (F.Y 2)) true
(* PR#4316 *)
module G(S : sig val x : int Lazy.t end) = struct include S end
module M1 = struct let x = lazy 3 end
let _ = Lazy.force M1.x
module rec M2 : sig val x : int Lazy.t end = G(M1)
let _ =
test 102 (Lazy.force M2.x) 3
let _ = Gc.full_major() (* will shortcut forwarding in M1.x *)
module rec M3 : sig val x : int Lazy.t end = G(M1)
let _ =
test 103 (Lazy.force M3.x) 3
(** Pure type-checking tests: see recmod/*.ml *)