Result
Result types are really useful to describe the result of a certain operation
without relying on exceptions or option
types.
This module gives you useful utilities to create and combine Result
data.
t
REStype t<'a, 'b> =
| Ok('a)
| Error('b)
The type Result.t(result, err)
describes a variant of two states:
Ok(someResult)
represents a successful operation, whereby
``Error(someError)` signals an erronous operation.
In this concrete example, we are defining our own Result
type to reflect an HTTP like
query operation:
REStype responseError = NotAvailable | NotFound
type queryResult = t<string, responseError>
let failQueryUser = (username: string): queryResult => {
Error(NotAvailable)
}
getExn
RESlet getExn: t<'a, 'b> => 'a
getExn(res)
: when res
is Ok(n)
, returns n
when res
is Error(m)
, raise an exception
RESBelt.Result.getExn(Belt.Result.Ok(42)) == 42
Belt.Result.getExn(Belt.Result.Error("Invalid data")) /* raises exception */
mapWithDefaultU
RESlet mapWithDefaultU: (t<'a, 'c>, 'b, (. 'a) => 'b) => 'b
mapWithDefault
RESlet mapWithDefault: (t<'a, 'c>, 'b, 'a => 'b) => 'b
mapWithDefault(res, default, f)
: When res is Ok(n)
, returns f(n)
,
otherwise default
.
RESlet ok = Belt.Result.Ok(42)
Belt.Result.mapWithDefault(ok, 0, (x) => x / 2) == 21
let error = Belt.Result.Error("Invalid data")
Belt.Result.mapWithDefault(error, 0, (x) => x / 2) == 0
mapU
RESlet mapU: (t<'a, 'c>, (. 'a) => 'b) => t<'b, 'c>
map
RESlet map: (t<'a, 'c>, 'a => 'b) => t<'b, 'c>
map(res, f)
: When res is Ok(n)
, returns Ok(f(n))
. Otherwise returns res
unchanged. Function f
takes a value of the same type as n
and returns an
ordinary value.
RESlet f = (x) => sqrt(Belt.Int.toFloat(x))
Belt.Result.map(Ok(64), f) == Ok(8.0)
Belt.Result.map(Error("Invalid data"), f) == Error("Invalid data")
flatMapU
RESlet flatMapU: (t<'a, 'c>, (. 'a) => t<'b, 'c>) => t<'b, 'c>
flatMap
RESlet flatMap: (t<'a, 'c>, 'a => t<'b, 'c>) => t<'b, 'c>
flatMap(res, f)
: When res is Ok(n)
, returns f(n)
. Otherwise, returns res
unchanged. Function f
takes a value of the same type as n
and returns a
Belt.Result
.
RESlet recip = (x) =>
if (x !== 0.0) {
Belt.Result.Ok(1.0 /. x)
} else {
Belt.Result.Error("Divide by zero")
}
Belt.Result.flatMap(Ok(2.0), recip) == Ok(0.5)
Belt.Result.flatMap(Ok(0.0), recip) == Error("Divide by zero")
Belt.Result.flatMap(Error("Already bad"), recip) == Error("Already bad")
getWithDefault
RESlet getWithDefault: (t<'a, 'b>, 'a) => 'a
getWithDefault(res, defaultValue)
: If res
is Ok(n)
, returns n
,
otherwise default
RESBelt.Result.getWithDefault(Ok(42), 0) == 42
Belt.Result.getWithDefault(Error("Invalid Data"), 0) == 0
isOk
RESlet isOk: t<'a, 'b> => bool
isOk(res)
: Returns true
if res
is of the form Ok(n)
, false
if it is
the Error(e)
variant.
isError
RESlet isError: t<'a, 'b> => bool
isError(res)
: Returns true
if res
is of the form Error(e)
, false
if
it is the Ok(n)
variant.
eqU
RESlet eqU: (t<'a, 'c>, t<'b, 'd>, (. 'a, 'b) => bool) => bool
eq
RESlet eq: (t<'a, 'c>, t<'b, 'd>, ('a, 'b) => bool) => bool
eq(res1, res2, f)
: Determine if two Belt.Result
variables are equal with
respect to an equality function. If res1
and res2
are of the form Ok(n)
and Ok(m)
, return the result of f(n, m)
. If one of res1
and res2
are of
the form Error(e)
, return false If both res1
and res2
are of the form
Error(e)
, return true
RESlet good1 = Belt.Result.Ok(42)
let good2 = Belt.Result.Ok(32)
let bad1 = Belt.Result.Error("invalid")
let bad2 = Belt.Result.Error("really invalid")
let mod10equal = (a, b) => mod(a, 10) === mod(b, 10)
Belt.Result.eq(good1, good2, mod10equal) == true
Belt.Result.eq(good1, bad1, mod10equal) == false
Belt.Result.eq(bad2, good2, mod10equal) == false
Belt.Result.eq(bad1, bad2, mod10equal) == true
cmpU
RESlet cmpU: (t<'a, 'c>, t<'b, 'd>, (. 'a, 'b) => int) => int
cmp
RESlet cmp: (t<'a, 'c>, t<'b, 'd>, ('a, 'b) => int) => int
cmp(res1, res2, f)
: Compare two Belt.Result
variables with respect to a
comparison function. The comparison function returns -1 if the first variable
is "less than" the second, 0 if the two variables are equal, and 1 if the first
is "greater than" the second.
If res1
and res2
are of the form Ok(n)
and Ok(m)
, return the result of
f(n, m)
. If res1
is of the form Error(e)
and res2
of the form Ok(n)
,
return -1 (nothing is less than something) If res1
is of the form Ok(n)
and
res2
of the form Error(e)
, return 1 (something is greater than nothing) If
both res1
and res2
are of the form Error(e)
, return 0 (equal)
RESlet good1 = Belt.Result.Ok(59)
let good2 = Belt.Result.Ok(37)
let bad1 = Belt.Result.Error("invalid")
let bad2 = Belt.Result.Error("really invalid")
let mod10cmp = (a, b) => Pervasives.compare(mod(a, 10), mod(b, 10))
Belt.Result.cmp(Ok(39), Ok(57), mod10cmp) == 1
Belt.Result.cmp(Ok(57), Ok(39), mod10cmp) == (-1)
Belt.Result.cmp(Ok(39), Error("y"), mod10cmp) == 1
Belt.Result.cmp(Error("x"), Ok(57), mod10cmp) == (-1)
Belt.Result.cmp(Error("x"), Error("y"), mod10cmp) == 0