[
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: | 2000-11-19 (14:50) |
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