Errors in OCaml

In OCaml, error handling is typically done using the Result type, which is similar to Go’s approach of returning explicit error values. The Result type has two variants: Ok for successful operations and Error for error conditions.

(* We'll use the Result module for error handling *)
open Base

(* A function that may return an error *)
let f arg =
  if arg = 42 then
    Error "can't work with 42"
  else
    Ok (arg + 3)

(* Predefined error values *)
let err_out_of_tea = Error.of_string "no more tea available"
let err_power = Error.of_string "can't boil water"

(* A function that uses predefined errors *)
let make_tea arg =
  match arg with
  | 2 -> Error err_out_of_tea
  | 4 -> Error (Error.tag ~tag:"making tea" err_power)
  | _ -> Ok ()

let () =
  (* Demonstrating error handling with f *)
  List.iter [7; 42] ~f:(fun i ->
    match f i with
    | Ok r -> Printf.printf "f worked: %d\n" r
    | Error e -> Printf.printf "f failed: %s\n" e
  );

  (* Demonstrating error handling with make_tea *)
  List.iter (List.range 0 5) ~f:(fun i ->
    match make_tea i with
    | Ok () -> Printf.printf "Tea is ready!\n"
    | Error e ->
      if Error.equal e err_out_of_tea then
        Printf.printf "We should buy new tea!\n"
      else if Error.(equal (strip (tag e)) err_power) then
        Printf.printf "Now it is dark.\n"
      else
        Printf.printf "unknown error: %s\n" (Error.to_string_hum e)
  )

In this OCaml version:

  1. We use the Result type to represent operations that might fail.

  2. The f function returns a Result type, with Ok for success and Error for failure.

  3. We define sentinel errors using Error.of_string.

  4. The make_tea function demonstrates how to return predefined errors.

  5. Error wrapping is achieved using Error.tag.

  6. In the main part of the program, we use pattern matching to handle the Result types returned by our functions.

  7. We use Error.equal to check for specific errors, similar to Go’s errors.Is.

  8. For wrapped errors, we use Error.strip and Error.tag to check the underlying error.

To run this program, save it as errors.ml and compile it with:

$ ocamlbuild -pkg base errors.native
$ ./errors.native
f worked: 10
f failed: can't work with 42
Tea is ready!
Tea is ready!
We should buy new tea!
Tea is ready!
Now it is dark.

This OCaml version demonstrates error handling techniques that are idiomatic to OCaml while maintaining the structure and logic of the original example.