Pvem: Home

Play with Error-Monads in OCaml

PVEM actually stands for “Polymorphic Variants-based Error Monads.”

Usage

The basic idea of these modules is to manipulate:

type ('ok, 'error) result = [
  | `Ok of 'ok
  | `Error of 'error
]

or combinations of that type (why polymorphic variants? see some implementation notes).

When you open Pvem (or include) in your source, you get

  • the module Result which implements the interface ERROR_MONAD with the above type,
  • the functor With_deferred: DEFERREDDEFERRED_RESULT which builds “error-monads” out of `Lwt`-like concurrency monads.

Since the monad(s) become pervasive; the ERROR_MONAD module type defines 3 infix operators:

  • >>= (ERROR_MONAD.bind): the “standard” bind operator.
  • >>| (ERROR_MONAD.map): pass the value through a “pure” function.
  • >>< (ERROR_MONAD.destruct): “reopen” the error monad to be able to match on both the “Ok” and “Error” cases; then return inside the monad like with bind.

Examples

Infix Operators

Here is a basic usage example for the 3 infix operators:

open Pvem
open Result

let fail_on_42 : int -> (int, string) Result.t =
  function 42 -> fail "42" | other -> return other

let f_uses_bind_and_return: int -> (float, string) Result.t = fun x ->
  fail_on_42 x
  >>= fun not_42 ->
  return (2. *. float not_42)

let f_uses_map: int -> (int * int, string) Result.t = fun x ->
  fail_on_42 x
  >>| (fun x -> (x, x))

let f_uses_destruct: int -> (float, string * string) Result.t = fun x ->
  fail_on_42 x
  >>< function
  | `Ok o -> return (float o)
  | `Error s -> fail ("did not convert to float", s)

Functor

To get an error monad on top of Lwt, simply

module Deferred_result = Pvem.With_deferred(Lwt)

With Jane Street's Async Deferred.t:

open Core_kernel.Std
open Async.Std
module Deferred_result = Pvem.With_deferred(struct
    include Deferred
    let catch tri wiz =
      Async.Std.try_with tri
      >>= function
      | Ok o -> return o
      | Error e -> wiz e
  end)