Version française
Home     About     Download     Resources     Contact us    
Browse thread
unwind-protect?
[ Home ] [ Index: by date | by threads ]
[ Search: ]

[ Message by date: previous | next ] [ Message in thread: previous | next ] [ Thread: previous | next ]
Date: -- (:)
From: CREGUT Pierre FTRD/DTL/LAN <pierre.cregut@r...>
Subject: Re: unwind-protect?
Pierre's solution repeat chdir which is often the long part of the code.
I like to use the following constructs (I am looking for smarter constructs.
I am also looking for a standard way of doing it that would go in the
standard library) :

  type 'a result = Normal of 'a | Exception of exn
  let catch f a = try Normal (f a) with e -> Exception e
  let throw = function Normal a -> a | Exception e -> raise e
  let with_fallback v f fallback = 
    match v with Normal a -> f a | Exception e -> fallback e

There are some contexts where it is as ubiquitous as the 'a option type.
For example, RPC on cin : 

  let cout, msg = sync(receive cin) in sync(send (catch f msg))

On the other side you will find :

  let channel = new_channel () in
  sync(send (channel,msg)); throw (sync (receive channel))  

In the chdir problem (or if you use any kind of lock construct) you can write :

  chdir ...;
  let r = catch (f a);
  chdir ...;
  throw r

The with_fallback function can be used to simulate the so much missing

   trylet .... in .... with ...

capturing only errors in the let part.

Pierre


                            ANNEX
                            =====

i am not convinced that with_fallback is the definitive answer for a fine 
grained control of exceptions.  To complete a previous post, I would prefer a 
new "context" construct

let complex_function .... =
  try
    let v = context c1 f x1 x2 ... in
    ....
    g (context c2 h y1 y2 ...) z1 z2 ...
    ...
  with
    E1 in c1 -> ....
  | E2 in c2 -> ....
  | E -> ....

Combined with a tool like ocamlexc, you can  
- have readable code that separates exceptional cases from the regular
  treatment.
- be sure that all your exceptions are trapped
- be convinced that your error handling code is trapping the right exception
  not another one that happened to have the same name (typical of Not_found
  exception handlers). 
(Note that the "looped approximation' of recursive datatype by ocamlexc could
limit the power of the analysis as we use an exception containing another
exception.)

Here is a crude prototype in CAMLP4 (lists are not needed, but you must
remember which context is embedded in which one. There are also issues
with tail recursion that can be broken.

********** exc.ml *************
exception Located of exn * string list
 
let extract = function Located(e,l) -> e,l | e -> e,[]
 
let present exc l = List.mem exc l      

**********excemption.ml*************
open Pcaml
open MLast

let match_case = Grammar.Entry.find expr "match_case"
let try_case = Grammar.Entry.create Pcaml.gram "try_case"

DELETE_RULE
  expr: "try"; expr; "with"; OPT "|"; LIST1 match_case SEP "|"
END

EXTEND
  expr :
   [ [ "try"; x = expr; "with"; OPT "|"; l = LIST1 try_case SEP "|" ->
        let l' = l @ [(<:patt<_>>,None,<:expr<raise _exc_>>)] in
        <:expr< try $x$ with [ _exc_ ->
            let (_e_,_loc_) = Exc.extract _exc_ in
            match _e_ with [ $list:l'$ ] ] >>
    | "context"; name =  UIDENT; e = expr ->
        <:expr<
           try $e$ with
           [  Exc.Located(e,l) -> raise (Exc.Located(e, [ $str:name$ :: l]))
           | e -> raise (Exc.Located(e,[$str:name$]))] >> ]]
  ;
  try_case :
    [[ p = patt; aso = OPT [ "as"; p = patt -> p ];
       at_location = OPT ["in"; location = UIDENT -> location];
       w_opt = OPT [ "when"; e = expr -> e ]; "->"; e = expr ->
          let p_with_as =
            match aso with
              Some as_pat -> <:patt< ($p$ as $as_pat$) >>
            | _ -> p in
          let w_with_at =
            begin match w_opt,at_location with
            | Some w,Some lc -> Some(<:expr<($w$) && (Exc.present $str:lc$ _loc_)>>)
            | None,Some lc -> Some (<:expr<Exc.present $str:lc$ _loc_>>)
            | _,None -> w_opt
            end in
          (p_with_as, w_with_at, e) ]]
  ;
END  


-- 
Pierre Cregut - pierre.cregut@rd.francetelecom.fr - +33 2 96 05 16 28
FTR&D - DTL/MSV - 2 avenue Pierre Marzin - 22307 Lannion Cedex - France