From mboxrd@z Thu Jan 1 00:00:00 1970 Received: (from weis@localhost) by pauillac.inria.fr (8.7.6/8.7.3) id PAA27935 for caml-red; Wed, 9 Aug 2000 15:54:29 +0200 (MET DST) Received: from nez-perce.inria.fr (nez-perce.inria.fr [192.93.2.78]) by pauillac.inria.fr (8.7.6/8.7.3) with ESMTP id CAA20990 for ; Wed, 9 Aug 2000 02:25:23 +0200 (MET DST) Received: from csla.csl.sri.com (csla.csl.sri.com [192.12.33.2]) by nez-perce.inria.fr (8.10.0/8.10.0) with ESMTP id e790PLX24992 for ; Wed, 9 Aug 2000 02:25:22 +0200 (MET DST) Received: from cylinder.csl.sri.com (IDENT:root@cylinder.csl.sri.com [130.107.15.112]) by csla.csl.sri.com (8.9.1/8.9.1) with ESMTP id RAA26114; Tue, 8 Aug 2000 17:25:15 -0700 (PDT) Received: (from filliatr@localhost) by cylinder.csl.sri.com (8.9.3/8.8.7) id RAA26445; Tue, 8 Aug 2000 17:25:14 -0700 X-Authentication-Warning: cylinder.csl.sri.com: filliatr set sender to filliatr@cylinder.csl.sri.com using -f From: Jean-Christophe Filliatre MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Message-ID: <14736.42218.740379.901126@cylinder.csl.sri.com> Date: Tue, 8 Aug 2000 17:25:14 -0700 (PDT) To: Michael Welsh Duggan Cc: caml-list@inria.fr Subject: Re: Recursive Sets? In-Reply-To: References: X-Mailer: VM 6.62 under Emacs 20.7.1 Reply-To: filliatr@csl.sri.com (Jean-Christophe Filliatre) Sender: weis@pauillac.inria.fr In his message of August 2, 2000, Michael Welsh Duggan writes: > I have been trying to create a recursive type which can express sets > of itself. The following code is not meant to be correct (it isn't), > but hopefully expresses the sort of thing I want to do. Can someone > throw some ideas at me? > > type foo = > | A | B > | Set of FooSet.t > > module OrderedFoos = > struct > type t = foo > let compare (a:t) (b:t) = compare a b > end > > module FooSet = Set.Make(OrderedFoos) Actually, the above code would be incorrect, even if ocaml would allow mutually recursive types and modules. Indeed, you cannot use Pervasives.compare to compare sets, since sets with the same elements may have different structural representation, and therefore would not give a comparison value of 0. (Otherwise, there would have been a solution: to make a polymorphic copy of Set with Pervasives.compare as a built-in comparison, Pset, and then to define type foo = A | B | foo Pset.t; I posted such a module Pset on this mailing list a few weeks ago). However, there is at least one solution to your problem, which is to mutually recursively define the types of elements and the type of sets, and to mutually recursively define the function to compare elements and to compare sets. If you take for instance the implementation of sets from the ocaml standard library, you get the code that I join below. I choose an arbitrary order relation for the elements (constructors are ordered like this: A < B < S) but of course you can take any other one. The nice thing is that you can still have the representation of sets abstract, by giving that module a signature like: ====================================================================== type t type elt = A | B | S of t val empty : t val add : elt -> t -> t ... ====================================================================== Hope this helps, -- Jean-Christophe Filliatre Computer Science Laboratory Phone (650) 859-5173 SRI International FAX (650) 859-2844 333 Ravenswood Ave. email filliatr@csl.sri.com Menlo Park, CA 94025, USA web http://www.csl.sri.com/~filliatr ====================================================================== (* This code is an adaptation of ocaml's standard library module Set. *) type elt = A | B | S of t and t = Empty | Node of t * elt * t * int (* Comparisons. *) let rec compare_elt e1 e2 = match e1,e2 with | A, A -> 0 | A, _ -> -1 | B, A -> 1 | B, B -> 0 | B, S _ -> -1 | S s1, S s2 -> compare s1 s2 | S _, _ -> 1 and compare_aux l1 l2 = match (l1, l2) with ([], []) -> 0 | ([], _) -> -1 | (_, []) -> 1 | (Empty :: t1, Empty :: t2) -> compare_aux t1 t2 | (Node(Empty, v1, r1, _) :: t1, Node(Empty, v2, r2, _) :: t2) -> let c = compare_elt v1 v2 in if c <> 0 then c else compare_aux (r1::t1) (r2::t2) | (Node(l1, v1, r1, _) :: t1, t2) -> compare_aux (l1 :: Node(Empty, v1, r1, 0) :: t1) t2 | (t1, Node(l2, v2, r2, _) :: t2) -> compare_aux t1 (l2 :: Node(Empty, v2, r2, 0) :: t2) and compare s1 s2 = compare_aux [s1] [s2] (* Sets are represented by balanced binary trees (the heights of the children differ by at most 2 *) let height = function Empty -> 0 | Node(_, _, _, h) -> h (* Creates a new node with left son l, value x and right son r. l and r must be balanced and | height l - height r | <= 2. Inline expansion of height for better speed. *) let create l x r = let hl = match l with Empty -> 0 | Node(_,_,_,h) -> h in let hr = match r with Empty -> 0 | Node(_,_,_,h) -> h in Node(l, x, r, (if hl >= hr then hl + 1 else hr + 1)) (* Same as create, but performs one step of rebalancing if necessary. Assumes l and r balanced. Inline expansion of create for better speed in the most frequent case where no rebalancing is required. *) let bal l x r = let hl = match l with Empty -> 0 | Node(_,_,_,h) -> h in let hr = match r with Empty -> 0 | Node(_,_,_,h) -> h in if hl > hr + 2 then begin match l with Empty -> invalid_arg "Set.bal" | Node(ll, lv, lr, _) -> if height ll >= height lr then create ll lv (create lr x r) else begin match lr with Empty -> invalid_arg "Set.bal" | Node(lrl, lrv, lrr, _)-> create (create ll lv lrl) lrv (create lrr x r) end end else if hr > hl + 2 then begin match r with Empty -> invalid_arg "Set.bal" | Node(rl, rv, rr, _) -> if height rr >= height rl then create (create l x rl) rv rr else begin match rl with Empty -> invalid_arg "Set.bal" | Node(rll, rlv, rlr, _) -> create (create l x rll) rlv (create rlr rv rr) end end else Node(l, x, r, (if hl >= hr then hl + 1 else hr + 1)) (* Same as bal, but repeat rebalancing until the final result is balanced. *) let rec join l x r = match bal l x r with Empty -> invalid_arg "Set.join" | Node(l', x', r', _) as t' -> let d = height l' - height r' in if d < -2 or d > 2 then join l' x' r' else t' (* Merge two trees l and r into one. All elements of l must precede the elements of r. Assumes | height l - height r | <= 2. *) let rec merge t1 t2 = match (t1, t2) with (Empty, t) -> t | (t, Empty) -> t | (Node(l1, v1, r1, h1), Node(l2, v2, r2, h2)) -> bal l1 v1 (bal (merge r1 l2) v2 r2) (* Same as merge, but does not assume anything about l and r. *) let rec concat t1 t2 = match (t1, t2) with (Empty, t) -> t | (t, Empty) -> t | (Node(l1, v1, r1, h1), Node(l2, v2, r2, h2)) -> join l1 v1 (join (concat r1 l2) v2 r2) (* Splitting *) let rec split x = function Empty -> (Empty, None, Empty) | Node(l, v, r, _) -> let c = compare_elt x v in if c = 0 then (l, Some v, r) else if c < 0 then let (ll, vl, rl) = split x l in (ll, vl, join rl v r) else let (lr, vr, rr) = split x r in (join l v lr, vr, rr) (* Implementation of the set operations *) let empty = Empty let is_empty = function Empty -> true | _ -> false let rec mem x = function Empty -> false | Node(l, v, r, _) -> let c = compare_elt x v in c = 0 || mem x (if c < 0 then l else r) let rec add x = function Empty -> Node(Empty, x, Empty, 1) | Node(l, v, r, _) as t -> let c = compare_elt x v in if c = 0 then t else if c < 0 then bal (add x l) v r else bal l v (add x r) let singleton x = Node(Empty, x, Empty, 1) let rec remove x = function Empty -> Empty | Node(l, v, r, _) -> let c = compare_elt x v in if c = 0 then merge l r else if c < 0 then bal (remove x l) v r else bal l v (remove x r) let rec union s1 s2 = match (s1, s2) with (Empty, t2) -> t2 | (t1, Empty) -> t1 | (Node(l1, v1, r1, h1), Node(l2, v2, r2, h2)) -> if h1 >= h2 then if h2 = 1 then add v2 s1 else begin let (l2, _, r2) = split v1 s2 in join (union l1 l2) v1 (union r1 r2) end else if h1 = 1 then add v1 s2 else begin let (l1, _, r1) = split v2 s1 in join (union l1 l2) v2 (union r1 r2) end let rec inter s1 s2 = match (s1, s2) with (Empty, t2) -> Empty | (t1, Empty) -> Empty | (Node(l1, v1, r1, _), t2) -> match split v1 t2 with (l2, None, r2) -> concat (inter l1 l2) (inter r1 r2) | (l2, Some _, r2) -> join (inter l1 l2) v1 (inter r1 r2) let rec diff s1 s2 = match (s1, s2) with (Empty, t2) -> Empty | (t1, Empty) -> t1 | (Node(l1, v1, r1, _), t2) -> match split v1 t2 with (l2, None, r2) -> join (diff l1 l2) v1 (diff r1 r2) | (l2, Some _, r2) -> concat (diff l1 l2) (diff r1 r2) let equal s1 s2 = compare s1 s2 = 0 let rec subset s1 s2 = match (s1, s2) with Empty, _ -> true | _, Empty -> false | Node (l1, v1, r1, _), (Node (l2, v2, r2, _) as t2) -> let c = compare_elt v1 v2 in if c = 0 then subset l1 l2 && subset r1 r2 else if c < 0 then subset (Node (l1, v1, Empty, 0)) l2 && subset r1 t2 else subset (Node (Empty, v1, r1, 0)) r2 && subset l1 t2 let rec iter f = function Empty -> () | Node(l, v, r, _) -> iter f l; f v; iter f r let rec fold f s accu = match s with Empty -> accu | Node(l, v, r, _) -> fold f l (f v (fold f r accu)) let rec for_all p = function Empty -> true | Node(l, v, r, _) -> p v && for_all p l && for_all p r let rec exists p = function Empty -> false | Node(l, v, r, _) -> p v || exists p l || exists p r let filter p s = let rec filt accu = function | Empty -> accu | Node(l, v, r, _) -> filt (filt (if p v then add v accu else accu) l) r in filt Empty s let partition p s = let rec part (t, f as accu) = function | Empty -> accu | Node(l, v, r, _) -> part (part (if p v then (add v t, f) else (t, add v f)) l) r in part (Empty, Empty) s let rec cardinal = function Empty -> 0 | Node(l, v, r, _) -> cardinal l + 1 + cardinal r let rec elements_aux accu = function Empty -> accu | Node(l, v, r, _) -> elements_aux (v :: elements_aux accu r) l let elements s = elements_aux [] s let rec min_elt = function Empty -> raise Not_found | Node(Empty, v, r, _) -> v | Node(l, v, r, _) -> min_elt l let rec max_elt = function Empty -> raise Not_found | Node(l, v, Empty, _) -> v | Node(l, v, r, _) -> max_elt r let choose = min_elt ======================================================================