From: Doug Bagley <doug@bagley.org>
To: Caml List <caml-list@inria.fr>
Subject: [Caml-list] beginner question about camlp4
Date: 22 Jan 2002 20:45:10 -0600 [thread overview]
Message-ID: <m38zapkcp5.fsf@ns.bagley.org> (raw)
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
next reply other threads:[~2002-01-23 8:05 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2002-01-23 2:45 Doug Bagley [this message]
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
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=m38zapkcp5.fsf@ns.bagley.org \
--to=doug@bagley.org \
--cc=caml-list@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