caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
* Re: unwind-protect?
@ 2000-11-17 14:01 Damien Doligez
  2000-11-21  9:36 ` unwind-protect? Pierre Weis
  0 siblings, 1 reply; 6+ messages in thread
From: Damien Doligez @ 2000-11-17 14:01 UTC (permalink / raw)
  To: caml-list

>From: Pierre Weis <Pierre.Weis@inria.fr>

>Here, polymorphism, curryfication, and specialization are shining,
>since you juste have to add one in_* functional application before an
>actual call to any function f to obtain a specialized evaluation
>context for f. For instance:

>let in_tmp f arg = in_directory "/tmp" f arg;;

Actually, currying gets in the way in this case (as it often does).
If f takes two arguments, then "in_tmp f x y" will not work as
expected, but the type-checker will not find the error.

-- Damien



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

* Re: unwind-protect?
  2000-11-17 14:01 unwind-protect? Damien Doligez
@ 2000-11-21  9:36 ` Pierre Weis
  0 siblings, 0 replies; 6+ messages in thread
From: Pierre Weis @ 2000-11-21  9:36 UTC (permalink / raw)
  To: Damien Doligez; +Cc: caml-list

> >From: Pierre Weis <Pierre.Weis@inria.fr>
> 
> >Here, polymorphism, curryfication, and specialization are shining,
> >since you juste have to add one in_* functional application before an
> >actual call to any function f to obtain a specialized evaluation
> >context for f. For instance:
> 
> >let in_tmp f arg = in_directory "/tmp" f arg;;
> 
> Actually, currying gets in the way in this case (as it often does).
> If f takes two arguments, then "in_tmp f x y" will not work as
> expected, but the type-checker will not find the error.
> 
> -- Damien

Right, you have to know that this in_* functions protect the last
application of a function. Hence to apply a curried function you need
parens to partially apply the function, as in_tmp (f x y) z.

Alternatively, you can define your n-ary functions as having tupled
arguments and write in_tmp f (x, y, z) (then the typechecker will find
the ``arity'' errors).

If you had functions with specific arity built-in in the langage, you
would have to define multiple versions of the protect functions, one
for each arity, which is not so appealing...

Pierre Weis

INRIA, Projet Cristal, Pierre.Weis@inria.fr, http://cristal.inria.fr/~weis/




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

* Re: unwind-protect?
@ 2000-11-17 14:37 David McClain
  0 siblings, 0 replies; 6+ messages in thread
From: David McClain @ 2000-11-17 14:37 UTC (permalink / raw)
  To: caml-list

>Is there an equivalent of Lisp's `unwind-protect' or Java's
>"try...finally"?

Here is the version that I use. It expects two functions of no arguments --
one for the protected portion and one for cleanup that is invoked in any
event.

let unwind_protect fn exitfn =
  let rslt =
    try
      fn()
    with
 exn ->
   ignore(exitfn());
   raise exn
  in
    ignore(exitfn());
    rslt


- D.McClain




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

* Re: unwind-protect?
  2000-11-17 12:28 ` unwind-protect? Pierre Weis
@ 2000-11-17 13:54   ` CREGUT Pierre FTRD/DTL/LAN
  0 siblings, 0 replies; 6+ messages in thread
From: CREGUT Pierre FTRD/DTL/LAN @ 2000-11-17 13:54 UTC (permalink / raw)
  To: caml-list

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



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

* Re: unwind-protect?
  2000-11-17  6:23 unwind-protect? Colin Walters
@ 2000-11-17 12:28 ` Pierre Weis
  2000-11-17 13:54   ` unwind-protect? CREGUT Pierre FTRD/DTL/LAN
  0 siblings, 1 reply; 6+ messages in thread
From: Pierre Weis @ 2000-11-17 12:28 UTC (permalink / raw)
  To: Colin Walters; +Cc: caml-list

> Hello,
> 
> Is there an equivalent of Lisp's `unwind-protect' or Java's
> "try...finally"?  I wanted to write a function which changed to
> another directory temporarily, and I came up with:
> 
> let in_directory d f =
>   let olddir = Unix.getcwd() in
>   (Unix.chdir d;
>    f();
>    Unix.chdir olddir)
> 
> But this won't work if f throws an exception.  Any suggestions?

There is no special construct: the basic construct is powerful enough
to handle the construction: you just have to use pattern matching to
bound the exception and raise it again, after having properly set up
the global state.

let in_directory d f =
  let olddir = Unix.getcwd () in
  try
    Unix.chdir d;
    f ();
    Unix.chdir olddir
  with x -> Unix.chdir olddir; raise x;;
val in_directory : string -> (unit -> 'a) -> unit = <fun>

Note also that this scheme can be generalized to cases where you need
to apply a function to some argument and need to get the result of
that call:

let in_directory d f arg =
  let olddir = Unix.getcwd () in
  try
    Unix.chdir d;
    let r = f arg in
    Unix.chdir olddir;
    r
  with x -> Unix.chdir olddir; raise x;;

val in_directory : string -> ('a -> 'b) -> 'a -> 'b = <fun>

Here, polymorphism, curryfication, and specialization are shining,
since you juste have to add one in_* functional application before an
actual call to any function f to obtain a specialized evaluation
context for f. For instance:

let in_tmp f arg = in_directory "/tmp" f arg;;
val in_tmp : ('a -> 'b) -> 'a -> 'b = <fun>

let open_out_tmp fname = in_tmp open_out fname;;
val open_out_tmp : string -> out_channel = <fun>

Hope this helps,

Pierre Weis

INRIA, Projet Cristal, Pierre.Weis@inria.fr, http://cristal.inria.fr/~weis/




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

* unwind-protect?
@ 2000-11-17  6:23 Colin Walters
  2000-11-17 12:28 ` unwind-protect? Pierre Weis
  0 siblings, 1 reply; 6+ messages in thread
From: Colin Walters @ 2000-11-17  6:23 UTC (permalink / raw)
  To: caml-list

Hello,

Is there an equivalent of Lisp's `unwind-protect' or Java's
"try...finally"?  I wanted to write a function which changed to
another directory temporarily, and I came up with:

let in_directory d f =
  let olddir = Unix.getcwd() in
  (Unix.chdir d;
   f();
   Unix.chdir olddir)

But this won't work if f throws an exception.  Any suggestions?




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

end of thread, other threads:[~2000-11-21  9:36 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2000-11-17 14:01 unwind-protect? Damien Doligez
2000-11-21  9:36 ` unwind-protect? Pierre Weis
  -- strict thread matches above, loose matches on Subject: below --
2000-11-17 14:37 unwind-protect? David McClain
2000-11-17  6:23 unwind-protect? Colin Walters
2000-11-17 12:28 ` unwind-protect? Pierre Weis
2000-11-17 13:54   ` unwind-protect? CREGUT Pierre FTRD/DTL/LAN

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