(* Copyright F.Marchant 2007 GPL *)

module Integer =
  struct
    type t = int
    let compare = compare
  end  

module SetPlus(Set : Set.S) = struct
  include Set
  
  let of_list = List.fold_left (fun s x -> add x s) empty
  
  let split_element s = let e = choose s in (e, remove e s)
                            
  let print print_element s =
    Printf.printf "{";
    (try let (elt, sr) = split_element s in
       print_element elt;
       iter (fun e -> Printf.printf ", "; print_element e)
            sr
     with Not_found -> ());
    Printf.printf "}\n"
end

module IntSet = SetPlus( Set.Make( Integer ) )

let required = function
    Some x -> x
  | None -> assert false

module StepPermuter = struct

type ssp = SSP of
  (IntSet.t           (* Initial set *)
   * int list option  (* Current permutation, if remains. *)
   * (int * IntSet.t) (* Iterator of initial set *)
   * ssp option)      (* Permuter of remaining elements, if any. *)

let get (SSP (_, permut_option, _, _)) = permut_option

let rec normal_ret e s remains si =
    if IntSet.is_empty remains then
      SSP ( s, Some [e], si, None )
    else                                    
      let pi = start remains in
        SSP ( s, Some (e::required (get pi)), si, Some pi )

and start s =
  let (e, rem) as si = IntSet.split_element s in
    normal_ret e s rem si

let rec next (SSP ( s, _, si, pio)) =
  let end_ret () = SSP ( s, None, si, None ) in
    match pio with
    	  None -> end_ret ()
    	| Some pi -> let npi = next pi in
                   let (elem, rem) = si in
    match get npi with
      	None ->
         if IntSet.is_empty rem then
           end_ret ()
         else
        	 let (e, _) as nsi = IntSet.split_element rem in
              normal_ret e s (IntSet.remove e s) nsi
	    | Some npi2 ->
	  SSP( s,
	       Some (elem::npi2),
                     si,
                     Some npi )
end

let (<<) f g x = f (g x)

let print_int_list =
  Printf.printf "[%s]\n" << String.concat "; " << List.map string_of_int

let while_some get f next =
  let rec _while_some thing =
    match get thing with
        None -> ()
      | Some x -> f x; _while_some (next thing) in
    _while_some
  
let _ = while_some
          StepPermuter.get 
          print_int_list
          StepPermuter.next
          (StepPermuter.start (IntSet.of_list [11; 13; 47]))
(*
[11; 13; 47]
[11; 47; 13]
[13; 11; 47]
[13; 47; 11]
[47; 11; 13]
[47; 13; 11]
*)

This document was generated using caml2html