[
Home
]
[ Index:
by date
|
by threads
]
[ Message by date: previous | next ] [ Message in thread: previous | next ] [ Thread: previous | next ]
[ Message by date: previous | next ] [ Message in thread: previous | next ] [ Thread: previous | next ]
| Date: | -- (:) |
| From: | Jon Harrop <jon@f...> |
| Subject: | try .. finally .. |
This is a very useful construct found in many other languages including F#.
This construct can be implemented in OCaml as a macro. Martin Jambon gives an
example on his camlp4 tutorial:
(* The function that returns unique identifiers *)
let new_id =
let counter = ref 0 in
fun () ->
incr counter;
"__finally" ^ string_of_int !counter
(* The function that converts our syntax into a single OCaml expression,
i.e. an "expr" node of the syntax tree *)
let expand loc e1 e2 =
let id = new_id () in
let id_patt = <:patt< $lid:id$ >> in
let id_expr = <:expr< $lid:id$ >> in
<:expr<
let $id_patt$ =
try do { $e1$; None }
with [ exn -> Some exn ] in
do { $e2$;
match $id_expr$ with
[ None -> ()
| Some exn -> raise exn ] }
>>
(* The statement that extends the default grammar,
i.e. the regular syntax of OCaml if we use camlp4o
or the revised syntax if we use camlp4r *)
EXTEND
Pcaml.expr: LEVEL "expr1" [
[ "try"; e1 = Pcaml.expr; "finally"; e2 = Pcaml.expr -> expand loc e1 e2 ]
];
END;;
Just looking at this code, the creation of new identifiers with obfuscated
names in an attempt to avoid conflicts is rather ugly.
Can this functionality be implemented more elegantly in terms of an
unwind_protect function, moving the new identifiers into their own scope:
let unwind_protect f g =
let fin = ref false in
try
let x = f () in
fin := true;
g();
x
with exn when !fin ->
g();
raise exn
EXTEND
Pcaml.expr: LEVEL "expr1" [
[ "try"; e1 = Pcaml.expr; "finally"; e2 = Pcaml.expr ->
<:expr< unwind_protect (fun () -> $e1$) (fun () -> $e2$) >> ]
];
END
Is this a general observation about macros?
--
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
The F#.NET Journal
http://www.ffconsultancy.com/products/fsharp_journal/?e