caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
* [Caml-list] Module/functor question
@ 2004-03-14 19:05 ronniec95
  2004-03-14 19:22 ` Yamagata Yoriyuki
  0 siblings, 1 reply; 5+ messages in thread
From: ronniec95 @ 2004-03-14 19:05 UTC (permalink / raw)
  To: caml-list

Hello

I'm trying to acheive the following effect in Ocaml that I should be
able to do but am getting very confused with modules and functors...

I have a set of classes all with the structure:-

class Foo {
	Foo* create(std::string x);
	std::string toXml(Foo*);
	... /* Other methods */

	int m_x;
	std::string m_y;
	}
and I have a template function

template<typename T>
void serialisetoxml(T* x) { printf("%s\n",x->toXml().c_str());}

int main()
{
	Foo* f = new Foo(1,"hello");
	serialisetoxml(f);
}

The effect I want to acheive is to have a function that takes any module
that has a toXml function defined and invokes it somewhere.

The closest I got was

(*serialise.mli*)
type t (* this doesn't work...*)
module type Serialise
sig
	val create : Xml.xml -> t (*Using XML-Light here *)
	val to_xml : t -> Xml.xml
end
	

(*foo.mli*)
type t = { x : int ; y:int }
module Make
sig
	val create : Xml.xml -> t (*Using XML-Light here *)
	val to_xml : t -> Xml.xml
end

(*foo.ml*)
type t = { x : int ; y:int }
module Make : Serialiser =
struct
	let create (f: Xml.xml) = Xml.Element("Foo",[("x",string_of_int f.x);("y",f.y))])
	let to_xml (foo : t) = ...
	(* It thinks f is of type Serialiser.t and not Foo.t *)
end

(* main.ml *)
module Sender (C : Serialiser) =
	struct
		let serialisetoxml msg = print_string (Xml.to_string (C.as_xml msg))
	end

(* was hoping for something like this *)
let _ = let m = module Sender(Foo.Make) in
	m.serialisetoxml (Foo.Make (Xml.parse_from "..."));

but I cannot figure out how to declare Foo having a signature of
Serialiser and then use it in main somehow. Assume also that I have
lots of other modules which have same basic interface but additional
methods specific to the modules.

Any help appreciated.

Thanks,


Ronnie

-- 

-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


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

* Re: [Caml-list] Module/functor question
  2004-03-14 19:05 [Caml-list] Module/functor question ronniec95
@ 2004-03-14 19:22 ` Yamagata Yoriyuki
  2004-03-14 23:46   ` ronniec95
  0 siblings, 1 reply; 5+ messages in thread
From: Yamagata Yoriyuki @ 2004-03-14 19:22 UTC (permalink / raw)
  To: ronniec95; +Cc: caml-list

From: ronniec95@lineone.net
Subject: [Caml-list] Module/functor question
Date: Sun, 14 Mar 2004 19:05:28 +0000

> but I cannot figure out how to declare Foo having a signature of
> Serialiser and then use it in main somehow. Assume also that I have
> lots of other modules which have same basic interface but additional
> methods specific to the modules.

You do not need to declare.  Foo.Make will accept any module whose
signature is an *extension* of Serializer.

> (* was hoping for something like this *)
> let _ = let m = module Sender(Foo.Make) in
> 	m.serialisetoxml (Foo.Make (Xml.parse_from "..."));

By the way, a correct code would be

   let _ =
      let module M = Sender(Foo.Make) in
      M.serialisetoxml (Foo.Make (Xml.parse_from "..."));

--
Yamagata Yoriyuki

-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


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

* Re: [Caml-list] Module/functor question
  2004-03-14 19:22 ` Yamagata Yoriyuki
@ 2004-03-14 23:46   ` ronniec95
  2004-03-15 12:34     ` Andreas Rossberg
  0 siblings, 1 reply; 5+ messages in thread
From: ronniec95 @ 2004-03-14 23:46 UTC (permalink / raw)
  To: Yamagata Yoriyuki; +Cc: caml-list

On Mon, Mar 15, 2004 at 04:22:18AM +0900, Yamagata Yoriyuki wrote:
> From: ronniec95@lineone.net
> Subject: [Caml-list] Module/functor question
> Date: Sun, 14 Mar 2004 19:05:28 +0000
> 
> > but I cannot figure out how to declare Foo having a signature of
> > Serialiser and then use it in main somehow. Assume also that I have
> > lots of other modules which have same basic interface but additional
> > methods specific to the modules.
> 
> You do not need to declare.  Foo.Make will accept any module whose
> signature is an *extension* of Serializer.
> 
> > (* was hoping for something like this *)
> > let _ = let m = module Sender(Foo.Make) in
> > 	m.serialisetoxml (Foo.Make (Xml.parse_from "..."));
> 
> By the way, a correct code would be
> 
>    let _ =
>       let module M = Sender(Foo.Make) in
>       M.serialisetoxml (Foo.Make (Xml.parse_from "..."));
> 
> --
> Yamagata Yoriyuki

Thanks that helped a lot - well it does work! but I'm a bit puzzled by
the extra declarations I had to do... 

I've copied the exact code below since it's not that long. I wonder
about header.mli which has 'type t=u' in it which was the only way of
getting it all to fit together. Why do I have to do that? Is there
another a more Ocaml way that I should be tackling this problem (I guess
a more design rather than implementation question...?)

Thanks for any ideas.

Ronnie


------- Code ----------
(*Header.mli*)
type u

module Make :
    sig
        type t = u
        val as_xml : t -> Xml.xml
        val create : Xml.xml -> t
    end

(* A function to construct Header.u objects *)
val make : ?version:int -> ?msgtypeid:int -> string -> string -> string -> u

(*Header.ml*)

(* some utility functions *)
let datetimefmt = "%Y%m%dT%H%M%S"
let find_node name root =
    let rec find (lst : Xml.xml list) res = match lst with
    | []    -> if List.length res = 0 
               then failwith ("Node not found:" ^ name)
               else res
    | Xml.Element(id,_,_) as hd::tl when id = name  -> find tl (hd::res)
    | _::tl                                         -> find tl res
    in
        find (Xml.children root) []



type u= { version : int; created : Calendar.t; environment : string; msgtypeid : int; msgtype : string; originatorid : string; machineid: string; }

(* OK I want everything to have this signature at least *)
module type Constructor =
    sig
        type t = u
        val as_xml : t -> Xml.xml
        val create : Xml.xml -> t
    end

module Make : Constructor =
struct
    type t = u (* why do I need this?*)
    let as_xml d = 
        Xml.Element("Header",[ 
                ("MsgVersion",(string_of_int d.version));
                ("Created",(fun x -> Printer.CalendarPrinter.sprint
                datetimefmt x)d.created);
                ("Environment",d.environment);
                ("MsgTypeId",(string_of_int d.msgtypeid));
                ("MsgType",d.msgtype)],
                [Xml.Element("Originator",[
                    ("OriginatorId",d.originatorid);
                    ("MachineId",d.machineid)],[])])

    let create (root:Xml.xml) : t =
        let originator = List.hd (find_node "Originator" root) in
        {   version = int_of_string(Xml.attrib root "MsgVersion");
            created = ((fun x -> Printer.CalendarPrinter.from_fstring datetimefmt x)
            (Xml.attrib root "Created"));
            environment = Xml.attrib root "Environment";
            msgtypeid = int_of_string(Xml.attrib root "MsgTypeId");
            msgtype = Xml.attrib root "MsgType";
            originatorid = Xml.attrib originator "OriginatorId";
            machineid = Xml.attrib originator "MachineId"; }

end

let make ?(version = 1) ?(msgtypeid=1) msgtype originator env =
        { version = version; created = Calendar.now(); environment = env; msgtypeid = msgtypeid; msgtype = msgtype; originatorid = originator; machineid = Unix.gethostname(); }

(*****************************************
 * main.ml - thanks to Yamagata Yoriyuki 
 *****************************************)

(* Don't like declaring this AGAIN! in main*)
module type Constructor =
    sig
        type t
        val as_xml : t -> Xml.xml
        val create : Xml.xml -> t
    end


module MessageSender (C : Constructor) =
    struct
        let send msg = print_string (Xml.to_string (C.as_xml msg))
    end

let _ = 
    let module M = MessageSender(Header.Make) in
    M.send (Header.make "Header" "TestMessage" "DEV") (* this works now!!*)

-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


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

* Re: [Caml-list] Module/functor question
  2004-03-14 23:46   ` ronniec95
@ 2004-03-15 12:34     ` Andreas Rossberg
  2004-03-15 16:20       ` ronniec95
  0 siblings, 1 reply; 5+ messages in thread
From: Andreas Rossberg @ 2004-03-15 12:34 UTC (permalink / raw)
  To: ronniec95; +Cc: caml-list

ronniec95@lineone.net wrote:
> 
> I've copied the exact code below since it's not that long. I wonder
> about header.mli which has 'type t=u' in it which was the only way of
> getting it all to fit together. Why do I have to do that?

You don't have to, if you declare the types at the right places, i.e. 
inside the modules. Actually, you don't need the local modules at all, 
since compilation units are already modules. Here is the sketch of a 
simplified version (not tested).

   (* header.mli *)
   type t
   val as_xml : t -> Xml.xml
   val create : Xml.xml -> t
   val make : ?version:int -> ?msgtypeid:int ->
              string -> string -> string -> t

   (* header.ml *)
   type t = { version : int;
              created : Calendar.t;
              environment : string;
              msgtypeid : int;
              msgtype : string;
              originatorid : string;
              machineid: string; }
   let as_xml d = ...
   let create (root:Xml.xml) : t = ...
   let make ?(version = 1) ?(msgtypeid=1) msgtype originator env = ...

   (* main.ml *)
   module type CONSTRUCTOR =
   sig
       type t
       val as_xml : t -> Xml.xml
       val create : Xml.xml -> t
   end

   module MessageSender (C : CONSTRUCTOR) =
   struct
       let send msg = print_string (Xml.to_string (C.as_xml msg))
   end

   let _ =
       let module M = MessageSender(Header) in
       M.send (Header.make "Header" "TestMessage" "DEV")

-- 
Andreas Rossberg, rossberg@ps.uni-sb.de

Let's get rid of those possible thingies!  -- TB

-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


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

* Re: [Caml-list] Module/functor question
  2004-03-15 12:34     ` Andreas Rossberg
@ 2004-03-15 16:20       ` ronniec95
  0 siblings, 0 replies; 5+ messages in thread
From: ronniec95 @ 2004-03-15 16:20 UTC (permalink / raw)
  To: Andreas Rossberg; +Cc: caml-list

Thanks for that. It's all kind of starting to make sense now!!

I'll experiment a little more and hopefully should be able to get some buyin
at work for using Ocaml for our trading applications. Now the messaging
is working, along with XML transforms (thanks to all who helped). Just the
DB to do.....

Ronnie

>-- Original Message --
>Date: Mon, 15 Mar 2004 13:34:14 +0100
>From: Andreas Rossberg <rossberg@ps.uni-sb.de>
>To: ronniec95@lineone.net
>CC: caml-list@inria.fr
>Subject: Re: [Caml-list] Module/functor question
>
>
>ronniec95@lineone.net wrote:
>>
>> I've copied the exact code below since it's not that long. I wonder
>> about header.mli which has 'type t=u' in it which was the only way of
>> getting it all to fit together. Why do I have to do that?
>
>You don't have to, if you declare the types at the right places, i.e.
>inside the modules. Actually, you don't need the local modules at all,

>since compilation units are already modules. Here is the sketch of a
>simplified version (not tested).
>
>   (* header.mli *)
>   type t
>   val as_xml : t -> Xml.xml
>   val create : Xml.xml -> t
>   val make : ?version:int -> ?msgtypeid:int ->
>              string -> string -> string -> t
>
>   (* header.ml *)
>   type t = { version : int;
>              created : Calendar.t;
>              environment : string;
>              msgtypeid : int;
>              msgtype : string;
>              originatorid : string;
>              machineid: string; }
>   let as_xml d = ...
>   let create (root:Xml.xml) : t = ...
>   let make ?(version = 1) ?(msgtypeid=1) msgtype originator env = ...
>
>   (* main.ml *)
>   module type CONSTRUCTOR =
>   sig
>       type t
>       val as_xml : t -> Xml.xml
>       val create : Xml.xml -> t
>   end
>
>   module MessageSender (C : CONSTRUCTOR) =
>   struct
>       let send msg = print_string (Xml.to_string (C.as_xml msg))
>   end
>
>   let _ =
>       let module M = MessageSender(Header) in
>       M.send (Header.make "Header" "TestMessage" "DEV")
>
>--
>Andreas Rossberg, rossberg@ps.uni-sb.de
>
>Let's get rid of those possible thingies!  -- TB
>


-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


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

end of thread, other threads:[~2004-03-15 16:20 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2004-03-14 19:05 [Caml-list] Module/functor question ronniec95
2004-03-14 19:22 ` Yamagata Yoriyuki
2004-03-14 23:46   ` ronniec95
2004-03-15 12:34     ` Andreas Rossberg
2004-03-15 16:20       ` ronniec95

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).