[
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: | 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