2015 002 Addition of Either module + explicit openable constrcutor module
June 21, 2026 ยท View on GitHub
(* use this via open Either.Cons *)
signature EITHER_CONS =
sig
datatype ('left, 'right) either = INL of 'left | INR of 'right
end
signature EITHER =
sig
include EITHER_CONS
structure Cons : EITHER_CONS
val isLeft : ('left, 'right) either -> bool
val isRight : ('left, 'right) either -> bool
val asLeft : ('left, 'right) either -> 'left option
val asRight : ('left, 'right) either -> 'right option
val map : ('ldom -> 'lrng) * ('rdom -> 'rrng)
-> ('ldom, 'rdom) either
-> ('lrng, 'rrng) either
val app : ('left -> unit) * ('right -> unit)
-> ('left, 'right) either
-> unit
val fold : ('left * 'b -> 'b) * ('right * 'b -> 'b)
-> 'b
-> ('left, 'right) either
-> 'b
val proj : ('a, 'a) either -> 'a
val partition : (('left, 'right) either) list
-> ('left list * 'right list)
val mapLeft : ('ldom -> 'lrng)
-> ('ldom, 'rdom) either
-> ('lrng, 'rdom) either
val mapRight : ('rdom -> 'rrng)
-> ('ldom, 'rdom) either
-> ('ldom, 'rrng) either
val appLeft : ('left -> unit)
-> ('left, 'right) either
-> unit
val appRight : ('right -> unit)
-> ('left, 'right) either
-> unit
val bindRight : ('a -> ('left, 'b) either)
-> ('left, 'a) either
-> ('left, 'b) either
val bindLeft : ('a -> ('b, 'right) either)
-> ('a, 'right) either
-> ('b, 'right) either
val fromOption : 'l
-> 'r option
-> ('l, 'r) either
end
Background
This project started originally as John Reppy's Either module added as an smlpkg package. Based on the original BasisLibrary 2015-002 submission, but packaged to be accessible to the wider smlpkg ecosystem. Subsequently, the openable constructor addition was made for better ergonomics.
Openable constructor
It's nice to be able to use Either's constructors (INR and INL) without
prefixing, just like one can use SOME and NONE in the Basis library.
The problem with openining Either as-is is that there are several functions
in there that shadow standard Basis functions like map and app.
I wanted to be able to open the constructors only, while leaving the other functions
fully-prefixed. The solution I came up with is to define a separate signature
EITHER_CONS, which exposes only the constructors, and subsequently both open it in
the implementation and expose it as a member struct. So now you can:
> val prefixed_val = Either.INR 3;
val prefixed_val = INR 3: ('a, int) Either.either
> open Either.Cons;
datatype ('a, 'b) either = INL of 'a | INR of 'b
> val non_prefixed_val = INR 3;
val non_prefixed_val = INR 3: ('a, int) either
> prefixed_val = non_prefixed_val;
val it = true: bool
How to include this in your sml project
- Place the package in your
sml.pkgfile;
require {
github.com/pzel/sml-either 0.0.1
}
- Sync with upstream
smlpkg sync
- If everything goes well, you'll have
either.mlbin thelibhierarchy:
$ find lib/ | grep either.mlb
lib/github.com/pzel/sml-either/either.mlb
TODO:
- Run tests & build under mlton
- Run tests & build under poly(mlb)
- Set up CI