caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
* [Caml-list] Higher order functors over tuples
@ 2012-10-31  9:26 Ivan Gotovchits
  2012-10-31 11:09 ` Didier Cassirame
  0 siblings, 1 reply; 8+ messages in thread
From: Ivan Gotovchits @ 2012-10-31  9:26 UTC (permalink / raw)
  To: caml-list


Good day,

1. A problem in general 

In general, the problem is to compute a tuple of objects that have
types different, but conforming to the same interface, i.e., given a
group of modules (A,B,C), conforming to signature S to construct some 

   module M: functor(A:S) -> functor(B:S) -> functor(C:S) -> S

that will, in a some way, «map/reduce» computation on corresponding
modules.

The problem can be generalized further, but, it seems to me, that it is
already quite (too?) abstract.

As far as I can see, there is no ad hoc solution for this problem in
OCaml, except, of course, objects with their late binding. But, in some
circumstances, the late binding can be avoided. In particular, when
types of modules and their amount are known and fixed at compile time.


2. Particular problem 

For example, we have several different data generator modules conforming
to the signature 

   module type Generator = 
   sig
     type t
     type r
     val create: unit  -> t 
     val result: t -> r option  
     val step:   t -> t option 
   end

Each generator can be stepped forward and queried for a result. Generator
can expire, in such case it will return None as a result. I want to make a
«list» of different generators and do some arbitary iterations on them. 

The «list» can be made of pairs, using the cons (meta)constructor:

   module Cons :
     functor(G1:Generator) -> functor(G2:Generator) -> Generator

So, if I have three modules A,B,C, I can construct module

   M = Cons(A)(Cons(B)(C))

and call M.step, to move a chain of generators forward, or M.result to
get the current result.


3. Particular solution

Here is the implementation on Cons module (named ConsGenerator), that "steps"
contained generators in a sequence (swapping them on each step).

   module ConsGenerator
       (G1:Generator)
       (G2:Generator with type r = G1.r)
       : Generator with type r = G2.r = 
   struct
     type t =
       | G1G2 of (G1.t option * G2.t option )
       | G2G1 of (G2.t option * G1.t option )

     type r = G2.r

     let create () =
       G1G2 ((Some (G1.create ())), Some (G2.create ()))

     let step = function
       | G1G2 (g1, Some g2)   -> Some (G2G1 (G2.step g2, g1))
       | G2G1 (g2, Some g1)   -> Some (G1G2 (G1.step g1, g2))
       | G2G1 (Some g2, None) -> Some (G2G1 (G2.step g2, None))
       | G1G2 (Some g1, None) -> Some (G1G2 (G1.step g1, None))
       | G1G2 (None,None) | G2G1 (None,None) -> None

     let result = function
       | G1G2 (Some g1,_) -> G1.result g1
       | G2G1 (Some g2,_) -> G2.result g2
       | G1G2 (None,_) | G2G1 (None,_) -> None
   end

Function `proceed' iterates module M and print results

   let rec proceed oe = match M.step oe with 
     | Some oe -> begin 
       match M.result oe with
         | Some r -> print_int r; proceed oe
         | None   -> proceed oe
     end
     | None -> print_newline (); 
         print_endline "generator finished"      

Just for a completness of the example a pair of simple generators:

   module Odd : Generator with type r = int = struct
     type t = int
     type r = int
     let create () = -1
     let step v = if v < 10 then Some (v+2) else None
     let result v = if v <= 9 then Some v else None
   end

   module Even : Generator with type r = int = struct
     type t = int
     type r = int
     let create () = 0
     let step v = if v < 10 then Some (v+2) else None
     let result v = if v <= 8 then Some v else None
   end

and the result was
   # module M = Cons(Even)(Cons(Cons(Odd)(Even))(Even))
   # let _  = proceed (M.create ())
   22244618648365879
   generator finished
   - : unit = ()


4. Question

And now the questions!

1) Is there any idiomatic solution to this pattern?

2) If not, can my solution be improved in some way? And how?

3) My intution says that it can be solved with monads (Generator really
incapsulates side effects in a step. Several computation are combined in
one big chain... ). Am I right? If so, how to implement it in monads?

Thanks for reading down to this line =) Any comments are welcome!

P.S. Sorry for such a long article. I haven't enough brains to make it
shorter =)

-- 
         (__) 
         (oo) 
   /------\/ 
  / |    ||   
 *  /\---/\ 
    ~~   ~~   
...."Have you mooed today?"...

^ permalink raw reply	[flat|nested] 8+ messages in thread
* [Caml-list] Higher order functors over tuples
@ 2012-11-06 11:48 oleg
  0 siblings, 0 replies; 8+ messages in thread
From: oleg @ 2012-11-06 11:48 UTC (permalink / raw)
  To: ivg, Didier.Cassirame; +Cc: caml-list


Ivan Gotovchits wrote
> In general, the problem is to compute a tuple of objects that have
> types different, but conforming to the same interface
That seems to be the right problem for existentials -- which exist in
OCaml under the name of objects. Methods are the interface and fields
are private data. Of course we can get by with mere records -- but if
we have objects anyway we might as well use them.

> For example, we have several different data generator modules conforming
> to the signature

>    module type Generator =
>    sig
>      type t
>      type r
>      val create: unit  -> t
>      val result: t -> r option
>      val step:   t -> t option
>    end

> Each generator can be stepped forward and queried for a result. Generator
> can expire, in such case it will return None as a result. I want to make a
> ?list? of different generators and do some arbitary iterations on them.

Here is the implementation of that example using objects. It seems the
object implementation provides the same static assurances and
abstractions as the module implementation. Since generators can
expire, the effective number of generators does change
dynamically. The static tupling doesn't buy us much.

(* The interface of generators *)

class type ['r] generator = object ('self)
    method result : unit -> 'r option
    method step   : unit -> 'self option
end;;


(* Function `proceed' iterates over the generator and print results *)

let rec proceed : int generator -> unit = fun gen ->
  match gen#step () with
  | Some gen -> begin
      match gen#result () with
      | Some r -> print_int r; proceed gen
      | None   -> proceed gen
  end
  | None -> print_newline ();
      print_endline "generator finished"
;;

(* Just for a completness of the example a pair of simple generators: *)

class odd : int -> [int] generator = fun init -> object
    val v = init
    method step () = if v <= 10 then Some {< v = v + 2 >} else None
    method result () = if v <= 9 then Some v else None
end
;;

(* A different way to constrain the type *)
class even init = object (self : int #generator)
    val v = init
    method step () = if v <= 10 then Some {< v = v + 2 >} else None
    method result () = if v <= 8 then Some v else None
end
;;

(* Make a list of generators itself a generator *)

let gen_list : 'r generator list -> 'r generator = fun gens -> object
    val v = gens
    method step () = 
      let rec loop = function
	| [] -> None
	| h :: t -> 
	    begin match h#step () with 
            | None -> loop t
	    | Some gen -> Some {< v = t @ [gen]  >}
	    end
      in loop v

    (* find the first generator that gives a result *)
    method result () =
      let rec loop = function
	| [] -> None
	| h :: t -> 
	    begin match h#result () with 
            | None -> loop t
	    | r    ->  r
	    end
      in loop (List.rev v)
end
;;


let a_gen_list = gen_list [new even 0;
			   new odd (-1);
			   new even 0;
			   new even 0];;


proceed a_gen_list;;

212243446566878889999
generator finished


^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2012-11-30 14:16 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-10-31  9:26 [Caml-list] Higher order functors over tuples Ivan Gotovchits
2012-10-31 11:09 ` Didier Cassirame
2012-10-31 12:02   ` Ivan Gotovchits
2012-11-30 12:49   ` [Caml-list] ocamlc, ocamlopt stackoverflow on list Christophe Raffalli
2012-11-30 13:20     ` Gabriel Scherer
2012-11-30 13:31       ` Christophe Raffalli
2012-11-30 14:15         ` Gabriel Scherer
2012-11-06 11:48 [Caml-list] Higher order functors over tuples oleg

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).