Custom Errors in Standard ML

(* A custom error type usually has the suffix "Error". *)
datatype argError = ArgError of {arg: int, message: string}

(* Adding this toString function makes argError printable *)
fun toString (ArgError {arg, message}) =
    Int.toString arg ^ " - " ^ message

(* Function that might return an error *)
fun f arg =
    if arg = 42 then
        NONE
    else
        SOME (arg + 3)

(* Main function *)
fun main () =
    case f 42 of
        NONE =>
            let
                val err = ArgError {arg = 42, message = "can't work with it"}
            in
                print (Int.toString (#arg (case err of ArgError r => r)) ^ "\n");
                print (#message (case err of ArgError r => r) ^ "\n")
            end
      | SOME result =>
            print ("Result: " ^ Int.toString result ^ "\n")

(* Run the main function *)
val _ = main ()

In Standard ML, we don’t have a built-in error type like in some other languages. Instead, we use the Option type to represent potential failures. Here’s how the code works:

  1. We define a custom argError datatype to represent our error condition. It contains an arg (integer) and a message (string).

  2. We create a toString function for our argError type to make it easily printable.

  3. The f function returns NONE when the input is 42 (simulating an error condition), and SOME (arg + 3) otherwise.

  4. In the main function, we call f 42 and pattern match on the result:

    • If it’s NONE, we create an argError and print its components.
    • If it’s SOME result, we print the result.
  5. Finally, we call the main function to execute our program.

To run this program:

  1. Save it to a file, e.g., custom_errors.sml.
  2. Use an SML interpreter or compiler to run it. For example, with Standard ML of New Jersey (SML/NJ):
$ sml custom_errors.sml
42
can't work with it

This example demonstrates how to create and use custom error types in Standard ML, even though the language doesn’t have a built-in error handling mechanism like some other languages. Instead, it uses algebraic data types and pattern matching to achieve similar functionality.