General

The General structure contains miscellaneous definitions.

The exnName and exnMessage are important for dealing with uncaught exceptions in your programs. You should always have some exception handlers around a top-level function looking something like this.

val success = OS.Process.success
val failure = OS.Process.failure


fun run args =
let
    ...
in
    process args;
    success
end
handle 
  IO.Io {name, function, cause} =>
    (
        toErr(concat["IO Error ", name,
              " ", function,
              " ", exnMessage cause, "\n"]);
        failure
    )

| Fatal => (toErr "Aborting\n"; failure)

| InternalError msg =>
    (
        toErr(concat["Internal error, ", msg, "\n"]);
        failure
    )

(* misc exception *) 
| x =>
    (
        toErr(concat["Uncaught exception: ", exnMessage x,"\n"]);
        failure
    )

I usually have a Fatal exception to abort a program upon a fatal error. Each site that detects the error produces an error message and raises Fatal to abort the program. I also have an InternalError exception to report all places that should be unreachabled. Each site that raises InternalError must include a message that uniquely identifiers the site for debugging. The last handler above catches all other exceptions and describes them.

The functions ! and := for dereferencing and assignment of imperative variables are defined here. Assignment is made infix with a precedence in the top-level environment. Dereference is an ordinary prefix function and so you will normally need to use parentheses around it. For example f !x is interpreted as a call to the function f with two arguments, ! and x when you probably meant f (!x).

The function o composes two functions together. It is sometimes useful when passing a combination of functions as an argument. For example a function map (lookup o uppercase) could be applied to a list of strings to replace each one by converting it to uppercase and then passing it through a lookup function.

The before function looks a bit odd. You can use it to attach tracing messages to expressions. For example

let
    ....
in
    print "starting f\n";
    f x before print "done f\n"
end