English version
Accueil     À propos     Téléchargement     Ressources     Contactez-nous    

Ce site est rarement mis à jour. Pour les informations les plus récentes, rendez-vous sur le nouveau site OCaml à l'adresse ocaml.org.

Browse thread
[ Home ] [ Index: by date | by threads ]
[ Search: ]

[ Message by date: previous | next ] [ Message in thread: previous | next ] [ Thread: previous | next ]
Date: 2000-11-17 (12:31)
From: Pierre Weis <Pierre.Weis@i...>
Subject: Re: unwind-protect?
> 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
    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
    Unix.chdir d;
    let r = f arg in
    Unix.chdir olddir;
  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/