caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
* try .. finally ..
@ 2007-05-20 17:42 Jon Harrop
  2007-05-20 19:30 ` [Caml-list] " Alain Frisch
  0 siblings, 1 reply; 3+ messages in thread
From: Jon Harrop @ 2007-05-20 17:42 UTC (permalink / raw)
  To: caml-list


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


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

* Re: [Caml-list] try .. finally ..
  2007-05-20 17:42 try .. finally Jon Harrop
@ 2007-05-20 19:30 ` Alain Frisch
  2007-05-21  7:49   ` Florian Weimer
  0 siblings, 1 reply; 3+ messages in thread
From: Alain Frisch @ 2007-05-20 19:30 UTC (permalink / raw)
  To: Jon Harrop; +Cc: caml-list

Jon Harrop wrote:
> (* 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 ] }
>   >>

Note that this implementation breaks tail positions of e2 (when no
exception is raised in e1, one might want to preserve tail-calls in e2
-- or not)...

>   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

and this one too, and you want (not !fin) instead of !fin.

Why not:

let unwind_protect f g =
  match (try f (); None with exn -> Some exn) with
   | None -> g ()
   | Some exn -> g (); raise exn

?




In the original version, I believe one could always use the same
identifier, without any extra conflicts. In the second version, you also
need to reserve one identifier (unwind_protect); of course, you can
inline its definition.

> Is this a general observation about macros?

If you mean that regular OCaml abstractions are better behaved w.r.t. to
the binding of identifiers than Camlp4 macros, I'd say the answer is yes.

-- Alain


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

* Re: [Caml-list] try .. finally ..
  2007-05-20 19:30 ` [Caml-list] " Alain Frisch
@ 2007-05-21  7:49   ` Florian Weimer
  0 siblings, 0 replies; 3+ messages in thread
From: Florian Weimer @ 2007-05-21  7:49 UTC (permalink / raw)
  To: Alain Frisch; +Cc: Jon Harrop, caml-list

* Alain Frisch:

> Why not:
>
> let unwind_protect f g =
>   match (try f (); None with exn -> Some exn) with
>    | None -> g ()
>    | Some exn -> g (); raise exn
>
> ?

unwind_protect traditionally returns the value of f (), not that of
g ().  I think it is fundamentally non-tail-call.


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

end of thread, other threads:[~2007-05-21  7:49 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-05-20 17:42 try .. finally Jon Harrop
2007-05-20 19:30 ` [Caml-list] " Alain Frisch
2007-05-21  7:49   ` Florian Weimer

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