Mailing list for all users of the OCaml language and system.
 help / color / mirror / Atom feed
* [Caml-list] beginner question about camlp4
@ 2002-01-23  2:45 Doug Bagley
  2002-01-23 10:15 ` Daniel de Rauglaudre
  2002-01-23 19:43 ` Charles Martin
  0 siblings, 2 replies; 5+ messages in thread
From: Doug Bagley @ 2002-01-23  2:45 UTC (permalink / raw)
  To: Caml List

Greetings,

I'm just learning about camlp4, and I was wondering if anyone would
care to comment on how I'm starting to go about it. If neither the
subject of camlp4, nor reading the random wanderings of newbies is of
interest, then please hit "n" now :)

First, I chose a simple problem: extending the exception syntax with
an "always" clause, to allow easy cleanup. My motivation came from
haing previously written a few I/O routines that look sort of like
this:

  let chan = open_something () in
  try
    process chan;
    close chan
  with
    Ouch -> close chan; maybe_do_something
  | e    -> close chan; raise e

(BTW, this finalization idiom is also mentioned in the caml docs). 
It works, but hey, it looks like we repeat ourselves calling "close
chan"! So, I thought maybe I could use camlp4 to write the code like
this instead:

  let chan = open_something () in
  try
    process chan;
  always
    close chan
  with
    Ouch -> maybe_do_something
  | e    -> raise e

Which I think looks a little cleaner. (Or, anyway provides a good
exercise for learning camlp4 :)

In my first attempt I decided to use an inner try block to catch all
exceptions. In its expanded form, it specifies the cleanup expression
(see $a$ below) in only 2 places, like so:

  EXTEND
    expr: LEVEL "expr1"
    [[ "try"; e = expr; "always"; a = expr; 
       "with"; OPT "|"; l = LIST1 
       [[ x1 = patt; w = OPT [ "when"; e = expr -> e ]; "->";
          x2 = expr -> (x1, w, x2 )
       ]] SEP "|" -> 
       <:expr<
          try do {
            try do {$e$; $a$} with ex -> do {$a$; raise ex}
          } with [$list:l$] >>
    ]];
  END;;

(The biggest reason I chose this implementation first was that it
wasn't immediately apparent to me how to manipulate $list:l$ to
produce code like what I originally started with). 

In this case, the produced code will look something like this:

  let chan = open_in "file" in
  try
    try
      begin process chan end;
      close chan
    with
      ex -> close chan; raise ex
  with
    Ouch -> maybe_do_something
  | e -> raise e;;
  
After learning a little more, I found out it wasn't so hard to get
what I'd originally planned, like this:

  EXTEND
    expr: LEVEL "expr1"
    [[ "try"; e = expr; "always"; a = expr; 
       "with"; OPT "|"; l = LIST1 
       [[ x1 = patt; w = OPT [ "when"; e = expr -> e ]; "->"; 
  	x2 = expr -> (x1, w, x2)
       ]] SEP "|" ->
       let l = List.map (fun (g,h,i) -> (g,h,<:expr< do{$a$;$i$} >>)) l in
         <:expr<  try do { $e$; $a$ } with [$list:l$] >>
    ]];
  END;;
  
Which produces code that looks something like this:
  
  let chan = open_in "file" in
  try
    begin process chan end;
    close chan
  with
    Ouch -> close chan; maybe_do_something
  | e -> close chan; raise e;;

Which looks good to me.


So my questions to the gurus are:
- Is one solution particularly better than the other?  (Do I lose or
  gain anything by using the inner try block?)
- Have I written any bad camlp4 here?  Please let me know if I've used
  anything in an incorrect manner or am guilty of bad style.
- Is this a worthwhile use of camlp4?  


P.S. Incidentally, before I tried camlp4, I had come up with a HOF to
encapsulate cleanup for exceptions, like this:

let safely setup cleanup subject f =
  let x = setup subject in
  try f x; cleanup x with e -> cleanup x; raise e

Which threads a value x through the setup/processing/cleanup functions,
and works fine for processing files, for instance, where x is the opened
channel, for example:

  safely open_in close_in "somefile" process_channel;

But in complicated situations, using this function becomes a little
hard to follow, like if I'm nesting a few file opens.

I happened to notice that FORT also uses pretty much the same HOF to
do cleanups too, so maybe I'm not the only one who thinks simplifying
finalization is a nice thing?

cheers,
doug
-------------------
Bug reports: http://caml.inria.fr/bin/caml-bugs  FAQ: http://caml.inria.fr/FAQ/
To unsubscribe, mail caml-list-request@inria.fr  Archives: http://caml.inria.fr


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

end of thread, other threads:[~2002-01-24 15:52 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2002-01-23  2:45 [Caml-list] beginner question about camlp4 Doug Bagley
2002-01-23 10:15 ` Daniel de Rauglaudre
2002-01-23 19:43 ` Charles Martin
2002-01-23 20:00   ` Doug Bagley
2002-01-23 21:48     ` Charles Martin

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox