From: "Netconsult International" <netconsult@hexabyte.tn>
To: <caml-list@yquem.inria.fr>
Subject: Re: Caml-list Digest, Vol 32, Issue 71
Date: Tue, 26 Feb 2008 15:24:30 +0100 [thread overview]
Message-ID: <004d01c87883$4d5f76d0$01fea8c0@Netconsult> (raw)
In-Reply-To: <20080226140500.2094FBC70@yquem.inria.fr>
please remove my adress from you list
Best regards
----- Original Message -----
From: <caml-list-request@yquem.inria.fr>
To: <caml-list@yquem.inria.fr>
Sent: Tuesday, February 26, 2008 3:05 PM
Subject: Caml-list Digest, Vol 32, Issue 71
> Send Caml-list mailing list submissions to
> caml-list@yquem.inria.fr
>
> To subscribe or unsubscribe via the World Wide Web, visit
> http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list
> or, via email, send a message with subject or body 'help' to
> caml-list-request@yquem.inria.fr
>
> You can reach the person managing the list at
> caml-list-owner@yquem.inria.fr
>
> When replying, please edit your Subject line so it is more specific
> than "Re: Contents of Caml-list digest..."
>
>
> Today's Topics:
>
> 1. Objects, dynamic cast, Obj.magic abuse and dragons (Berke Durak)
> 2. Re: Objects, dynamic cast, Obj.magic abuse and dragons
> (Richard Jones)
> 3. Unexpected restriction in "let rec" expressions (Loup Vaillant)
> 4. Re: Objects, dynamic cast, Obj.magic abuse and dragons (ketti)
> 5. Re: Objects, dynamic cast, Obj.magic abuse and dragons
> (Berke Durak)
> 6. Re: Unexpected restriction in "let rec" expressions
> (Jean-Christophe Filli?tre)
>
>
> ----------------------------------------------------------------------
>
> Message: 1
> Date: Tue, 26 Feb 2008 12:35:10 +0100
> From: Berke Durak <berke.durak@exalead.com>
> Subject: [Caml-list] Objects, dynamic cast, Obj.magic abuse and
> dragons
> To: Caml-list List <caml-list@inria.fr>
> Message-ID: <47C3F96E.4080901@exalead.com>
> Content-Type: text/plain; charset="utf-8"
>
> Hello,
>
> It seems that objects are back in fashion again on the list.
>
> As records of functions or functors dont quite cut the mustard for some
> applications, I decided to give Ocaml's object
> system another try. I tried to implement a conventional text adventure
> using those, of the "go north take sword kill
> dragon" kind. Actually I had one such small prototype I wrote while
> learning Java, so I decided to port that one.
>
> I've stumbled on a situation where I feel dynamic casting could be useful.
> At least, that is the way I did it in the
> Java version. I've worked around it using Obj.magic, but I can't check
> the class, so this could lead to nastiness.
> I'd rather eat a runtime Class_cast_exception than a segmentation fault.
>
> In this adventure, things can contain other things; a class physical has a
> list of things it contains, and an optional
> pointer to its container.
>
> Persons, places and objects are things so they inherit from physical.
> Hence, a forest is a place that can contain
> a sword (an object), a dragon (a person) or another place (a small house).
> Persons can be contained in places
> or things (coffins).
>
> The problem is that the main game loop gets the current location by taking
> the container of the hero... which is a
> physical. However, it needs to call the place-specific method "go".
>
> I'm submitting my example so that you can propose alternative solutions.
> A few ideas:
>
> * Add a go method in physical, raise an exception - not scalable, if I
> want to add other categories of things,
> I'll have to add the corresponding method to physical.
> * Parametrize physical with the type of contents.
> * Use a sum type; but then it wouldn't be an object any more, and it's a
> centralized place.
> --
> Berke DURAK
> -------------- next part --------------
> (* Adventure *)
>
> exception QuitException
>
> let mandatory = function
> | None -> raise Not_found
> | Some x -> x
>
> let pf = Printf.printf
>
> let split_at c u =
> let m = String.length u in
> let b = Buffer.create m in
> let rec loop0 r i =
> if i >= m then
> List.rev r
> else
> if u.[i] = c then
> loop0 r (i + 1)
> else
> loop1 r i
> and loop1 r i =
> if i = m or u.[i] = c then
> begin
> let x = Buffer.contents b in
> Buffer.clear b;
> loop0 (x::r) (i + 1)
> end
> else
> begin
> Buffer.add_char b u.[i];
> loop1 r (i + 1)
> end
> in
> loop0 [] 0
>
> let ( & ) f x = f x
>
> class ['subject] io in_channel () =
> object
> val mutable subject : 'subject option = None
> method set_subject s = subject <- Some s
> method get_subject = mandatory subject
>
> method read =
> pf "< %!";
> split_at ' ' & input_line in_channel
>
> method write u =
> pf ">>> %s\n%!" u
> end
>
> class virtual command =
> object
> method virtual get_verb : string
> method virtual perform : string list -> unit
> end
>
> class virtual describable =
> object
> method virtual describe : 'a . 'a io -> unit
> method virtual get_name : string
> end
>
> class virtual physical =
> object(self)
> inherit describable as super
> val mass = 1.0
> val takeable = true
> val mutable contents : physical list = []
> val mutable container : physical option = None
> method contents = contents
> method container = mandatory container
>
> method add : physical -> unit = fun thing -> contents <- thing ::
> contents
>
> method remove (thing : physical) = contents <- List.filter ((<>) thing)
> contents
>
> method unlink =
> match container with
> | None -> ()
> | Some t -> t#remove (self :> physical)
>
> method put (target : physical) =
> self#unlink;
> container <- Some target;
> target#add (self :> physical)
>
> end
>
> class biscuit =
> object
> inherit physical as super
> method describe io =
> io#write "A square biscuit with chocolate in it. It is organic, or
> at least that's what the writing on it, presumably in edible, organic ink,
> says.";
> method get_name = "a chocolate biscuit"
> method to_string = "the biscuit"
> end
>
> type direction = N | S | E | W
>
> let invert = function
> | N -> S
> | S -> N
> | E -> W
> | W -> E
>
> let connect p1 d p2 =
> p1#connect d p2;
> p2#connect (invert d) p1
>
> class virtual place =
> object(self)
> inherit physical as super
> val mutable seen = false
> val mutable outlinks : (direction * place) list = []
>
> method go d = List.assoc d outlinks
>
> method connect d t = outlinks <- (d, t) :: outlinks
>
> method describe_items : 'a . 'a io -> unit = fun io ->
> io#write "You can see:";
> List.iter
> (fun p ->
> let (q : physical) = p in
> q#describe io
> )
> contents
>
> method virtual describe_place : 'a . 'a io -> unit
>
> method describe io =
> self#describe_place io;
> self#describe_items io
> end
>
> class virtual person =
> object
> inherit physical as super
> val takeable = false
> end
>
> class hero =
> object
> inherit person as super
> method get_name = "John"
> method describe io = io#write "John is a tall man."
> end
>
> let sf = Printf.sprintf
>
> class forest name () =
> object(self)
> inherit place as super
> method get_name = name
> method describe_place io =
> io#write (sf "You are in %s" self#get_name)
> end
>
> class sword =
> object(self)
> inherit physical as super
>
> method describe io =
> io#write "A one-meter long, titanium alloy, gold-plated,
> emerald-incrusted, Dragon-repelling adventurer's heavy duty sword."
>
> method get_name = "A golden sword"
> end
>
> class game io =
> let f1 = new forest "the big dark forest" () in
> let f2 = new forest "the small dark forest" () in
> let f3 = new forest "the small light forest" () in
> let f4 = new forest "the tropical forest" () in
> let h = new hero in
> let _ = h#put (f1 :> physical) in
> let _ = connect f1 N f2 in
> let _ = connect f2 E f3 in
> let _ = connect f3 S f4 in
> let _ = connect f4 E f1 in
> let _ = io#set_subject h in
> let sw = new sword in
> let _ = sw#put (f1 :> physical) in
> let b = new biscuit in
> let _ = b#put (f4 :> physical) in
> object(self)
> method where =
> let wh' = h#container in
> (* XXXXXXXX here *)
> let wh : place = Obj.magic wh' in (* I'd like a dynamic cast here! *)
> (* XXXXXXXX *)
> (*let wh' = (h#container : physical <: place) in*)
> wh
>
> method go d =
> try
> let wh = self#where in
> let wh = wh#go d in
> h#put (wh : place :> physical)
> with
> | Not_found ->
> io#write "Can't go there"
>
> method run =
> let wh = self#where in
> wh#describe io;
> begin
> match io#read with
> | ["n"] -> self#go N
> | ["s"] -> self#go S
> | ["e"] -> self#go E
> | ["w"] -> self#go W
> | _ -> io#write "Wtf?"
> end
> end
>
> let play () =
> let io = new io stdin () in
> let g = new game io in
> while true do
> g#run
> done
>
> ------------------------------
>
> Message: 2
> Date: Tue, 26 Feb 2008 12:14:51 +0000
> From: Richard Jones <rich@annexia.org>
> Subject: Re: [Caml-list] Objects, dynamic cast, Obj.magic abuse and
> dragons
> To: Berke Durak <berke.durak@exalead.com>
> Cc: Caml-list List <caml-list@inria.fr>
> Message-ID: <20080226121451.GA20860@annexia.org>
> Content-Type: text/plain; charset=us-ascii
>
> On Tue, Feb 26, 2008 at 12:35:10PM +0100, Berke Durak wrote:
>> The problem is that the main game loop gets the current location by
>> taking
>> the container of the hero... which is a physical. However, it needs to
>> call the place-specific method "go".
>
> I only briefly read over this, but maybe the thing you want is an
> object memo. There's a specialized one in lablgtk called GUtil.memo,
> but the basic source for it could be adapted:
>
> class ['a] memo () = object
> constraint 'a = #widget
> val tbl = Hashtbl.create 7
> method add (obj : 'a) =
> Hashtbl.add tbl obj#get_id obj
> method find (obj : widget) = Hashtbl.find tbl obj#get_id
> method remove (obj : widget) = Hashtbl.remove tbl obj#get_id
> end
>
> There's an example of using this if you search down for 'memo' on this
> page:
>
> http://www.ocaml-tutorial.org/introduction_to_gtk
>
> Rich.
>
> --
> Richard Jones
> Red Hat
>
>
>
> ------------------------------
>
> Message: 3
> Date: Tue, 26 Feb 2008 13:24:57 +0100
> From: "Loup Vaillant" <loup.vaillant@gmail.com>
> Subject: [Caml-list] Unexpected restriction in "let rec" expressions
> To: "Caml List" <caml-list@inria.fr>
> Message-ID:
> <6f9f8f4a0802260424o5bce2fd9i89fbfa38bb239a6a@mail.gmail.com>
> Content-Type: text/plain; charset=ISO-8859-1
>
> hello,
>
> I was trying to translate this simple Haskell definition in Ocaml:
>
> loop :: ((a,c) -> (b,c)) -> a -> b
> loop f a = b
> where (b,c) = f (a,c)
>
> However, the direct translation doesn't work:
>
> # let loop f a =
> let rec (b, c) = f (a, c) in
> b;;
> Characters 25-31:
> let rec (b, c) = f (a, c) in
> ^^^^^^
> Only variables are allowed as left-hand side of `let rec'
>
> So I try to bypass this restriction:
>
> # let loop f a =
> let rec couple = f (a, snd couple) in
> fst couple;;
> Characters 34-51:
> let rec couple = f (a, snd couple) in
> ^^^^^^^^^^^^^^^^^
> This kind of expression is not allowed as right-hand side of `let rec'
>
>
> Any ideas about what is this restriction, an what is it for?
>
> Thanks,
> Loup
>
>
>
> ------------------------------
>
> Message: 4
> Date: Tue, 26 Feb 2008 13:48:20 +0100
> From: ketti <kattlachan@gmail.com>
> Subject: Re: [Caml-list] Objects, dynamic cast, Obj.magic abuse and
> dragons
> To: "Berke Durak" <berke.durak@exalead.com>
> Cc: Caml-list List <caml-list@inria.fr>
> Message-ID:
> <6ebe51ce0802260448i61b968e4tf618edc0580636f5@mail.gmail.com>
> Content-Type: text/plain; charset=UTF-8
>
> Hi,
>
> 2008/2/26 Berke Durak <berke.durak@exalead.com>:
>> Persons, places and objects are things so they inherit from physical.
>> Hence, a forest is a place that can contain
>> a sword (an object), a dragon (a person) or another place (a small
>> house). Persons can be contained in places
>> or things (coffins).
>>
>> The problem is that the main game loop gets the current location by
>> taking the container of the hero... which is a
>> physical. However, it needs to call the place-specific method "go".
>
> I too have only read your code briefly, but i would suggest you use
> multiple inheritanse. Coffin would inherit from both object and place.
> That way the container of the hero is always a place. In fact, that is
> the way i would encode it in java too (using interfaces).
>
>
>
> ------------------------------
>
> Message: 5
> Date: Tue, 26 Feb 2008 14:10:13 +0100
> From: Berke Durak <berke.durak@exalead.com>
> Subject: Re: [Caml-list] Objects, dynamic cast, Obj.magic abuse and
> dragons
> Cc: Caml-list List <caml-list@inria.fr>
> Message-ID: <47C40FB5.1090603@exalead.com>
> Content-Type: text/plain; charset=UTF-8; format=flowed
>
> I have found a where, for each category C (such as place or person), you
> add a method
>
> as_C : C
>
> in physical that throws a Class_cast_exception, and override it with a
> method that returns
> self in class C. However this means that the type C must appear in the
> definition of physical,
> which means that either
>
> (a) All categories C1, ..., Cn are defined in the same file in the same
> bunch
> of mutually-recursive class definitions; a solution evidently not
> scalable.
>
> (b) The physical class is parametrized by n paramters 'C1, 'C2, ... 'Cn,
> which
> must be repeated everywhere.
>
> The latter solution works for small n but the complexity of incremental
> maintenance is in O(n).
> This means that if you define your n classes in n files, you'll have to
> edit n files to add
> an (n+1)-th class.
>
> This leads me back to an idea I was talking about with Yann Régis-Gianas
> a few months ago :
> the ability to bundle type parameters as a named record and to access
> their components.
>
> You could write, in a file
>
> f.ml:
> type ''bundle := ('place, 'person, 'c3, 'c4 ...)
>
> then in physical.ml :
>
> class [F.''bundle] physical =
> object
> method as_place : raise Class_cast_exception
> method as_person : raise Class_cast_exception
> method as_c3 : raise Class_cast_exception
> end
>
> and in place.ml
> class [F.''bundle] place =
> object(self : 'a)
> constraint ''bundle.'place = 'a
> method as_place = self
> end
>
> and so on... I don't know how much sense this makes with respect to
> separate compilation.
> However, this would allow you to add a category by just editing two files.
> --
> Berke DURAK
>
>
>
> ------------------------------
>
> Message: 6
> Date: Tue, 26 Feb 2008 15:04:44 +0100
> From: Jean-Christophe Filli?tre <Jean-Christophe.Filliatre@lri.fr>
> Subject: Re: [Caml-list] Unexpected restriction in "let rec"
> expressions
> To: Loup Vaillant <loup.vaillant@gmail.com>
> Cc: Caml List <caml-list@inria.fr>
> Message-ID: <47C41C7C.6010006@lri.fr>
> Content-Type: text/plain; charset=ISO-8859-1
>
> Loup Vaillant a écrit :
>> I was trying to translate this simple Haskell definition in Ocaml:
>>
>> loop :: ((a,c) -> (b,c)) -> a -> b
>> loop f a = b
>> where (b,c) = f (a,c)
>>
>> However, the direct translation doesn't work:
>>
>> # let loop f a =
>> let rec (b, c) = f (a, c) in
>> b;;
>> Characters 25-31:
>> let rec (b, c) = f (a, c) in
>> ^^^^^^
>> Only variables are allowed as left-hand side of `let rec'
>>
>> So I try to bypass this restriction:
>>
>> # let loop f a =
>> let rec couple = f (a, snd couple) in
>> fst couple;;
>> Characters 34-51:
>> let rec couple = f (a, snd couple) in
>> ^^^^^^^^^^^^^^^^^
>> This kind of expression is not allowed as right-hand side of `let rec'
>>
>>
>> Any ideas about what is this restriction, an what is it for?
>
> Ocaml has call-by-value, and it cannot figure out a value to be passed
> as f's second argument. To be convinced, just imagine that the type of
> this argument is empty (an empty type can be introduced by "type empty"
> without definition, for instance).
>
> --
> Jean-Christophe
>
>
>
> ------------------------------
>
> _______________________________________________
> Caml-list mailing list. Subscription management:
> http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list
> Archives: http://caml.inria.fr
> Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
> Bug reports: http://caml.inria.fr/bin/caml-bugs
>
>
> End of Caml-list Digest, Vol 32, Issue 71
> *****************************************
next parent reply other threads:[~2008-02-26 14:24 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <20080226140500.2094FBC70@yquem.inria.fr>
2008-02-26 14:24 ` Netconsult International [this message]
2008-02-26 19:36 ` [Caml-list] " Erik de Castro Lopo
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to='004d01c87883$4d5f76d0$01fea8c0@Netconsult' \
--to=netconsult@hexabyte.tn \
--cc=caml-list@yquem.inria.fr \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox