Module Prelude.Exn

Functions for working with exceptions.

val ignore : ('a -> unit) -> 'a -> unit

(ignore f x) is (f x) except that any exception is ignored.

val fold : ?exn:exn -> ('a -> 'b -> 'b) -> 'b -> 'a -> 'b

fold ?exn f acc x: tail-recursively nest applications of (f x acc) until f raises an exception.

If ~exn is given, only exn cleanly terminates the recursion and any other exception is reraised; otherwise, any exception terminates cleanly.

(fold f acc x) = (f x (... (f x (f x (f x (f x acc)))))) 

Example: this function counts the number of lines on an input channel:

fold (fun chan n -> Stdlib.ignore (input_line chan); succ n) 0 
val default : 'a -> ('b -> 'a) -> 'b -> 'a

default d f x: return (f x) unless an exception is raised, in which case return default value d.

val succeeds : ('a -> 'b) -> 'a -> bool

(succeeds f x) evaluates (f x) and returns true iff the evaluation did NOT raise an exception.

  • (succeeds f x) = (catch f x |> Option.something)
val reraise : ?this:exn -> exn -> ('a -> 'b) -> 'a -> 'b

(reraise exn f x) is (f x), converting any exception to exn.

Specifically, (reraise exn f x) is (f x) unless an exception is raised, in which case we instead raise exn.

(reraise ~this exn f x) is (f x) unless some exception e is raised, in which case we raise:

  • exn if (e = this)
  • e if (e <> this)
val finalize : ('a -> 'b) -> ('a -> unit) -> 'a -> 'b

finalize f g x: evaluate (f x), afterwards calling (g x) to finalize the resource x.

Evaluation of (g x) is guaranteed even if f raises an exception (which is re-raised).

Process the lines of a file, avoiding a file descriptor leak in the case that process raises an exception:

open_in "/etc/passwd" |> finalize process close_in 
val to_string : exn -> string

(to_string exn) produces a "better" (IMHO) representation of an exception for end users.

Specifically, Sys_error and Unix.Unix_error exceptions, the ones most often encountered by end users, are rendered like so:

Printexc.to_string: (Sys_error "X: No such file or directory")

Exn.to_string: X: No such file or directory

Printexc.to_string: Unix.Unix_error(Unix.ENOENT, "open", "X")

Exn.to_string: X: No such file or directory

All other exceptions are just passed to Printexc.to_string.

Labels

Short-circuiting Execution

return and label taken from Batteries. See OCaml Batteries Included.

type 'a label = 'a -> exn

The type of labels returning 'a.

val label : ('u label -> 'u) -> 'u

(label f) creates a label around the invocation of f, which is a computation that can be short-circuited (exited) via return.

Usage is: (label (fun l -> ... return l v ...; d)) where l is the label, v is the value to be returned, and d is the default value of the entire expression if return is never called.

Example: return immediately with (Some x), the first value < 10 in xs, presumably a long list of integers, or None if no such value is found: label (fun l -> iter (fun x -> if x < 10 then return l (Some x)) xs; None)

Compare this to:

foldl (fun r x -> if x < 10 && r = None then Some x else r) None xs 

which evaluates to the same value, but always examines every element of xs, where the label / return version stops at the first x < 10.

"label f creates a new label x and invokes f x. If, during the execution of f, return x v is invoked, the execution of f x stops immediately and label f returns v. Otherwise, if f x terminates normally and returns y, label f returns y.

Calling return x v from outside scope f is a run-time error and causes termination of the program." See Batteries.

val return : ('a -> exn) -> 'a -> 'b

(return label v) returns to the point where label was defined and has the value v.