(*
 * $Log: basic,v $
 * Revision 1.2  1998/05/28 15:25:30  jont
 * Automatic checkin:
 * changed attribute _comment to ' * '
 *
 *)               
          (*  CATEGORICAL PROGRAMS 0 *)


(* This is the file which should be compiled as a preliminary to the
   categorical programs. It contains operations on lists and sets *)

fun length nil = 0 |
    length (h :: t) = 1 + length t;

fun member (e, nil) = false |
    member (e :''a , (h :: t) :''a list ) = if (e=h) then true
                                             else member (e, t) ;

fun flat1 [] = [] |
    flat1 (h :: t) = h @ (flat1 t);

fun split_list [] = ([],[])  |
    split_list (h :: t) =
          let val (a,b) = split_list t 
          in
              if (length t) mod 2 = 0 then ([h] @ a,b)
              else (a,[h] @ b)
          end;

fun singlify  [] = [] |
    singlify  (h :: t) = 
       let val s = singlify t 
       in
           if member (h,t) then s
           else h :: s
       end;

fun remove_one x (h :: t) =
        if  (x=h) then t else h :: (remove_one x t) 
  | remove_one _ [] = [];

fun re_arrangement ([],[])       = true |
    re_arrangement ([],(h :: t)) = false |
    re_arrangement ((h :: t),[]) = false |
    re_arrangement ((h :: t),l2 as (h2 :: t2)) =
        if member (h,l2) then re_arrangement (t,remove_one h l2)
        else false;
                    
fun remove_all_of_one x (h :: t) =
        let val remove_from_tail = remove_all_of_one x t
        in if (x=h) then remove_from_tail
           else h :: remove_from_tail
        end |
    remove_all_of_one _ [] = [];

fun remove_all_of_many (h :: t) l =
        remove_all_of_one h (remove_all_of_many t l) |
    remove_all_of_many  [] l = l;


fun filter_list P []       = [] |
    filter_list P (h :: t) = let val ft = filter_list P t
                             in if P h then (h :: ft)
                                else ft
                             end;

fun pair_lists [] _ = [[]] |
    pair_lists (h :: t) l2 =
        let val hp = map (fn x => (h,x)) l2
            val tp = pair_lists t l2
            fun extend l = (map (fn p => p :: l) hp)
        in flat1 (map extend tp)
        end;

   

exception sing_split_nil_set
exception split_nil_set;

infix is_in
infix U
infix section
infix ==
infix mapset
infix within 
infix diff ;

        datatype 'a Set = set of 'a list;
   
        val nil_set = set([]);
        val emptyset = set([]);   (* Alternative name *)

        fun is_nil_set (set([])) = true |
            is_nil_set (set(h :: t)) = false ;
        fun is_empty(s) = is_nil_set(s);    (* Alternative name *)

        fun cardinality (set ([])) = 0 |
            cardinality (set (l as (_ :: _))) = length (singlify l); 
        fun cardinal (set ([])) = 0 |
            cardinal (set (l as (_ :: _))) = length (singlify l); 

        fun singleton e = set ([e]);
        fun is_singleton(s) = (cardinality(s)=1);

        fun  list_set (set ([])) = [] |
             list_set (set (l as (_ :: _))) = singlify l;

        fun (set([])) U s = s |
            (set(h :: t)) U (set(l2)) =
                 if member (h,l2) then
                           set(t) U set(l2)
                 else set(t) U set(h::l2);

        fun add(x,S) = singleton(x) U S;

        fun x is_in (set([])) = false |
            x is_in (set(l as (_ :: _))) = member (x,l);

        fun (set([])) section _ = set([])
          | (set(h :: t)) section s =
                 let val tsecn = set(t) section s
                 in
                     if h is_in s then set([h]) U tsecn
                     else tsecn
                 end;

        fun (set([])) diff _ = set([]) |
            (set(h :: t)) diff s =
                 let val tdiff = set(t) diff s 
                 in
                     if h is_in s then tdiff
                     else set([h]) U tdiff
                 end;

        fun singleton_split (set ([])) = raise sing_split_nil_set |
            singleton_split (set (h :: t)) = (h,set (t));


        fun element_of(s) = let val (x,_) = singleton_split(s) in x end;

        fun split (set ([])) = raise split_nil_set |
            split (set (h :: t)) =
                      let val (a,b) = split_list (h :: t) 
                      in 
                           (set(a),set(b))
                      end;

        fun (set([])) within _ = true |
            (set(h :: t)) within s =
                  (h is_in s)  andalso  (set(t) within s); 
        
        fun s1 == s2 = (s1 within s2) andalso (s2 within s1); 

        fun f mapset (set(l)) = set(map f l); 

        fun set_minus(set(t),x) = set(remove_all_of_one x t);

(*      fun mapset2 (f,set(l,_)) = set(map f l,eq); *)

        fun flatten_set (set(l)) = 
               let fun f (h :: t) = h U (f t) |
                       f []       = nil_set
               in f l
               end;

        fun enumerate show (set(l')) =
               let val l = singlify(l');
                   fun str_list sh [] = "" |
                       str_list sh (h :: []) = sh h |
                       str_list sh (h1 :: (h2 :: t)) =
                                 (sh h1) ^ "," ^ (str_list sh (h2 :: t))
               in "{" ^ (str_list show l) ^ "}"
               end; 



infix 5 *$
fun f *$ S = if is_nil_set S then nil_set
             else let val (e,S1) = singleton_split S
                  in (singleton(f e)) U (f *$ S1)
                  end;

(*  Several simple functions. *)

        exception nilfn;

	fun identity_fn a = a;
	
        fun nil_fn _ = raise nilfn;
        fun emptyfn _ = raise nilfn;

 	fun constant b = fn _ => b ;

	fun f o g = fn x => g(f(x)) ;

        infix **
        fun  f ** (a_set,a_value) =
             if is_nil_set a_set then a_value
             else let val (a,S) = singleton_split a_set
                  in f ** (S,f(a,a_value))
                  end;

	infix 3 X 
	fun  set1 X set2  =
            if is_nil_set set1 then nil_set
            else if is_nil_set set2 then nil_set
                 else let val (a,set3) = singleton_split set1
                          val s = (fn x => (a,x)) mapset set2
                      in s U (set3 X set2)
                      end;



        (*  multicompose : (num # 'a # ('a # 'a -> 'a) # 'a) -> 'a *)
(*        fun multicompose(zero,_,_,init) = init | *)
(*         multicompose(succ(n),F,comp,i) = comp(F,multicompose(n,F,comp,i)); *)


	(*   first :  (alpha*beta) -> alpha *)
	(*   second : (alpha*beta) -> beta *)

   	fun first(x,y)  = x;
	fun second(x,y) = y;

        infix filtered_by
        fun A filtered_by P =
                if is_nil_set A then nil_set
                else let val A_list = list_set A
                     in set (filter_list P A_list)
                     end;

        fun forall(S,p) = is_empty(S filtered_by (fn x => not(p x)));

        exception pairlist_to_fn;

        fun pair_list_to_fn  [] = nil_fn |
            pair_list_to_fn  (l as (_ :: _)) =
                  let fun  pair_off [] _ = raise pairlist_to_fn |
                           pair_off ((a,r) :: t) x = if  (x=a) then r
                                                        else pair_off t x
                  in pair_off l
                  end;

        fun powerset(S) = if is_empty(S) then singleton(S) else
                           let val (s,S') = singleton_split(S) 
                               val PS' = powerset(S') in
                           (add mapset (singleton(s) X PS')) U PS' end;

(* end *)

