Either

The Either type represents a value of one of two possible types. Unlike Result (which has success/error semantics), Either treats both sides as equally valid outcomes.

Import

import Either or import Types.Either

Type Definition

type Either a b
Left a | Right b
An Either value is either Left a or Right b. By convention, Left is the "alternative" case and Right is the "primary" case.
x = Left 42 : Either Int String
y = Right "hello" : Either Int String

Predicates

Either.is-left?
Either a b -> Bool
Returns true if the Either is a Left value.
Either.is-right?
Either a b -> Bool
Returns true if the Either is a Right value.
x = Left 42
println (Either.is-left? x)   # => true
println (Either.is-right? x)  # => false

Extraction

Either.left
Either a b -> Option a
Extract the Left value as an Option. Returns None if Right.
Either.right
Either a b -> Option b
Extract the Right value as an Option. Returns None if Left.
x = Right "hello"
match Either.right x
  | Some s -> println s
  | None -> println "was left"
# => "hello"
Either.unwrap-left-or
a -> Either a b -> a
Extract the Left value or return a default if Right.
Either.unwrap-right-or
b -> Either a b -> b
Extract the Right value or return a default if Left.
x = Left 42
println (Either.unwrap-right-or "default" x)
# => "default"

Mapping

Either.map-left
(a -> c) -> Either a b -> Either c b
Transform the Left value, leaving Right unchanged.
Either.map-right
(b -> c) -> Either a b -> Either a c
Transform the Right value, leaving Left unchanged.
x = Right 10
y = x |> Either.map-right (fn(n) => n * 2)
# => Right 20
Either.map-both
(a -> c) -> (b -> d) -> Either a b -> Either c d
Transform both sides with separate functions.
x = Left 5
y = Either.map-both (fn(n) => n * 2) String.length x
# => Left 10

Chaining

Either.and-then-left
(a -> Either c b) -> Either a b -> Either c b
Chain operations on the Left side. If Left, apply the function (which returns a new Either). If Right, pass through unchanged.
Either.and-then-right
(b -> Either a c) -> Either a b -> Either a c
Chain operations on the Right side. If Right, apply the function (which returns a new Either). If Left, pass through unchanged.

Folding

Either.fold
(a -> c) -> (b -> c) -> Either a b -> c
Eliminate an Either by providing functions for both cases. Both functions must return the same type.
x = Left 42
result = Either.fold
  (fn(n) => "Number: ${n}")
  (fn(s) => "String: ${s}")
  x
# => "Number: 42"
Either.merge
Either a a -> a
Merge an Either where both sides have the same type.
x = Left 42 : Either Int Int
println (Either.merge x)  # => 42
Either.swap
Either a b -> Either b a
Swap Left and Right.
x = Left 42
y = Either.swap x  # => Right 42

List Operations

Either.lefts
[Either a b] -> [a]
Extract all Left values from a list of Eithers.
Either.rights
[Either a b] -> [b]
Extract all Right values from a list of Eithers.
items = [Left 1, Right "a", Left 2, Right "b"]
println (Either.lefts items)   # => [1, 2]
println (Either.rights items)  # => ["a", "b"]
Either.partition
[Either a b] -> ([a], [b])
Partition a list of Eithers into a tuple of (lefts, rights).
items = [Left 1, Right "a", Left 2]
(ls, rs) = Either.partition items
# ls = [1, 2], rs = ["a"]

Conversion

Either.to-result
Either e a -> Result a e
Convert Either to Result. Left becomes Err, Right becomes Ok.
Either.from-result
Result a e -> Either e a
Convert Result to Either. Err becomes Left, Ok becomes Right.
Either.to-option
Either a b -> Option b
Convert Either to Option. Right becomes Some, Left becomes None.
x = Right 42
y = Left "error"
println (Either.to-option x)  # => Some 42
println (Either.to-option y)  # => None