Using Belt.Result
Belt.Result
defines a data type with two variants: Ok
and Error
. Each of these variants can
contain data, and those two pieces of data need not have the same data type. Belt.Result
is
useful when you need to not only determine whether some data is valid or not (use Belt.Option
for that), but also keep information about the invalid data.
In the examples, we presume the existence of two variables:
let good = Belt.Result.Ok(64)
let bad = Belt.Result.Error("Invalid data")
[@@@ocaml.ppx.context { cookies = [] }]
let good = ((Belt.Result.Ok (64))[@explicit_arity ])
let bad =
((Belt.Result.Error
((("Invalid data")[@reason.raw_literal "Invalid data"])))[@explicit_arity
])
Here are the functions that Belt.Result
supports.
getExn
Retrieve the value in an Ok(n)
result.
Sample call: getExn(res)
When res
is of the form Ok(n)
, returns n
When res
is of the form Error(e)
, raise an exception
Js.log(Belt.Result.getExn(good)); /* 64 */
Js.log(Belt.Result.getExn(bad)); /* raises exception */
[@@@ocaml.ppx.context { cookies = [] }]
let good = ((Belt.Result.Ok (64))[@explicit_arity ])
let bad =
((Belt.Result.Error
((("Invalid data")[@reason.raw_literal "Invalid data"])))[@explicit_arity
])
let _ = Js.log (Belt.Result.getExn good)
let _ = Js.log (Belt.Result.getExn bad)
getWithDefault
Retrieve the value in an Ok(n)
result, or provide a default if it is an Error(e)
.
Sample call: getWithDefault(res, default)
If res
is Ok(n)
, returns n
, otherwise default
Js.log(Belt.Result.getWithDefault(Ok(42), 0)); /* 42 */
Js.log(Belt.Result.getWithDefault(Error("Invalid Data"), 0)); /* 0 */
[@@@ocaml.ppx.context { cookies = [] }]
let _ = Js.log (Belt.Result.getWithDefault ((Ok (42))[@explicit_arity ]) 0)
let _ =
Js.log
(Belt.Result.getWithDefault
((Error ((("Invalid Data")[@reason.raw_literal "Invalid Data"])))
[@explicit_arity ]) 0)
mapWithDefault
This function allows you to pass a Belt.Result
argument to a function that has a non-Result
parameter and returns a non-Result
value.
The result of mapWithDefault
will be a non-Result
value.
Sample call: mapWithDefault(res, default, f)
When res
is of the form Ok(n)
, returns f(n)
, otherwise default
.
let half = (x) => x / 2
Js.log(Belt.Result.mapWithDefault(good, 0,half)); /* 32 */
Js.log(Belt.Result.mapWithDefault(bad, 0, half)); /* 0 */
[@@@ocaml.ppx.context { cookies = [] }]
let good = ((Belt.Result.Ok (64))[@explicit_arity ])
let bad =
((Belt.Result.Error
((("Invalid data")[@reason.raw_literal "Invalid data"])))[@explicit_arity
])
let half x = x / 2
let _ = Js.log (Belt.Result.mapWithDefault good 0 half)
let _ = Js.log (Belt.Result.mapWithDefault bad 0 half)
map
This function allows you to pass a Belt.Result
argument to a function that has a non-Result
parameter and return value.
The result of map
will be a Belt.Result
value.
Sample call: map(res, f)
When res
is of the formOk(n)
, returns Ok(f(n))
. Otherwise returns res
unchanged.
Function f
takes a value of the same type as n
and returns a non-Result
value.
let f = (x) => sqrt(float_of_int(x));
Js.log(Belt.Result.map(Ok(64), f)); /* Ok(8.0) */
Js.log(Belt.Result.map(Error("Invalid"), f)); /* Error("Invalid") */
[@@@ocaml.ppx.context { cookies = [] }]
let good = ((Belt.Result.Ok (64))[@explicit_arity ])
let bad =
((Belt.Result.Error
((("Invalid data")[@reason.raw_literal "Invalid data"])))[@explicit_arity
])
let f x = sqrt (float_of_int x)
let _ = Js.log (Belt.Result.map ((Ok (64))[@explicit_arity ]) f)
let _ =
Js.log
(Belt.Result.map
((Error ((("Invalid")[@reason.raw_literal "Invalid"])))[@explicit_arity
]) f)
flatMap
This function allows you to pass a Belt.Result
argument to a function that has a non-Result
parameter and returns a Belt.Result
value.
Sample call: 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
.
let reciprocal = (x) => {
if (x != 0.0) {
Belt.Result.Ok(1.0 /. x)
} else {
Belt.Result.Error("Divide by zero");
}
};
Js.log(Belt.Result.flatMap(Ok(2.0), reciprocal)); /* Ok(0.5) */
Js.log(Belt.Result.flatMap(Ok(0.0), reciprocal)); /* Error("Divide by zero") */
Js.log(Belt.Result.flatMap(Error("Already bad"),
reciprocal)); /* Error("Already bad")) */
[@@@ocaml.ppx.context { cookies = [] }]
let reciprocal x =
if x <> 0.0
then ((Belt.Result.Ok ((1.0 /. x)))[@explicit_arity ])
else
((Belt.Result.Error
((("Divide by zero")[@reason.raw_literal "Divide by zero"])))
[@explicit_arity ])
let _ =
Js.log (Belt.Result.flatMap ((Ok (2.0))[@explicit_arity ]) reciprocal)
let _ =
Js.log (Belt.Result.flatMap ((Ok (0.0))[@explicit_arity ]) reciprocal)
let _ =
Js.log
(Belt.Result.flatMap
((Error ((("Already bad")[@reason.raw_literal "Already bad"])))
[@explicit_arity ]) reciprocal)
isOk
Sample call: isOk(res)
Returns true
if res
is of the form Ok(n)
, false
if it is the Error(e)
variant.
Js.log(Belt.Result.isOk(good)); /* true */
Js.log(Belt.Result.isOk(bad)); /* false */
[@@@ocaml.ppx.context { cookies = [] }]
let good = ((Belt.Result.Ok (64))[@explicit_arity ])
let bad =
((Belt.Result.Error
((("Invalid data")[@reason.raw_literal "Invalid data"])))[@explicit_arity
])
let _ = Js.log (Belt.Result.isOk good)
let _ = Js.log (Belt.Result.isOk bad)
isError
Sample call: isError(res)
Returns true
if res
is of the form Error(e)
, false
if it is the Ok(n)
variant.
Js.log(Belt.Result.isError(good)); /* false */
Js.log(Belt.Result.isError(bad)); /* true */
[@@@ocaml.ppx.context { cookies = [] }]
let good = ((Belt.Result.Ok (64))[@explicit_arity ])
let bad =
((Belt.Result.Error
((("Invalid data")[@reason.raw_literal "Invalid data"])))[@explicit_arity
])
let _ = Js.log (Belt.Result.isError good)
let _ = Js.log (Belt.Result.isError bad)
eq
Determine if two Belt.Result
variables are equal with respect to an equality function.
Sample call: eq(res1, res2, f)
- If
res1
andres2
are of the formOk(n)
andOk(m)
, return the result off(n,m)
. - If one of
res1
andres2
are of the formError(e)
, returnfalse
; iff bothres1
andres2
are of the formError(e)
, returntrue
.
let 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) => {
a mod 10 == b mod 10
};
Js.log(Belt.Result.eq(good1, good2, mod10equal)); /* true */
Js.log(Belt.Result.eq(good1, bad1, mod10equal)); /* false */
Js.log(Belt.Result.eq(bad2, good2, mod10equal)); /* false */
Js.log(Belt.Result.eq(bad1, bad2, mod10equal)); /* true */
[@@@ocaml.ppx.context { cookies = [] }]
let good1 = ((Belt.Result.Ok (42))[@explicit_arity ])
let good2 = ((Belt.Result.Ok (32))[@explicit_arity ])
let bad1 =
((Belt.Result.Error ((("invalid")[@reason.raw_literal "invalid"])))
[@explicit_arity ])
let bad2 =
((Belt.Result.Error
((("really invalid")[@reason.raw_literal "really invalid"])))[@explicit_arity
])
let mod10equal a b = (a mod 10) = (b mod 10)
let _ = Js.log (Belt.Result.eq good1 good2 mod10equal)
let _ = Js.log (Belt.Result.eq good1 bad1 mod10equal)
let _ = Js.log (Belt.Result.eq bad2 good2 mod10equal)
let _ = Js.log (Belt.Result.eq bad1 bad2 mod10equal)
cmp
Compare two Belt.Result
variables with respect to a comparison function.
Sample call: cmp(res1, res2, f)
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
andres2
are of the formOk(n)
andOk(m)
, return the result off(n, m)
. - If
res1
is of the formError(e)
andres2
of the formOk(n)
, return -1 (nothing is less than something). - If
res1
is of the formOk(n)
andres2
of the formError(e)
, return 1 (something is greater than nothing). - If both
res1
andres2
are of the formError(e)
, return 0 (equal)
let mod10cmp = (a, b) => {
Pervasives.compare((a mod 10), (b mod 10))
};
Js.log(Belt.Result.cmp(Ok(39), Ok(57), mod10cmp)); /* 1 */
Js.log(Belt.Result.cmp(Ok(57), Ok(39), mod10cmp)); /* -1 */
Js.log(Belt.Result.cmp(Ok(39), Error("y"), mod10cmp)); /* 1 */
Js.log(Belt.Result.cmp(Error("x"), Ok(57), mod10cmp)); /* -1 */
Js.log(Belt.Result.cmp(Error("x"), Error("y"), mod10cmp)); /* 0 */
[@@@ocaml.ppx.context { cookies = [] }]
let mod10cmp a b = Pervasives.compare (a mod 10) (b mod 10)
let _ =
Js.log
(Belt.Result.cmp ((Ok (39))[@explicit_arity ])
((Ok (57))[@explicit_arity ]) mod10cmp)
let _ =
Js.log
(Belt.Result.cmp ((Ok (57))[@explicit_arity ])
((Ok (39))[@explicit_arity ]) mod10cmp)
let _ =
Js.log
(Belt.Result.cmp ((Ok (39))[@explicit_arity ])
((Error ((("y")[@reason.raw_literal "y"])))[@explicit_arity ])
mod10cmp)
let _ =
Js.log
(Belt.Result.cmp
((Error ((("x")[@reason.raw_literal "x"])))[@explicit_arity ])
((Ok (57))[@explicit_arity ]) mod10cmp)
let _ =
Js.log
(Belt.Result.cmp
((Error ((("x")[@reason.raw_literal "x"])))[@explicit_arity ])
((Error ((("y")[@reason.raw_literal "y"])))[@explicit_arity ])
mod10cmp)
Uncurried Versions of Functions
Some of the functions in this module have uncurried versions. In ReasonML, if you don’t provide all the arguments to a function, you get a new, partially-applied function (this is called “currying”). When you are interoperating with JavaScript, however, this can be a problem. If you don’t provide all the arguments, JavaScript can’t detect that at compile time. Instead, any missing argument problems will show up at runtime. See this page for more details
To solve this problem, the functions that have more than one parameter have uncurried versions. Their name ends with a capital U
. They have the same arguments in the same order, but you must provide all the arguments when you call them. The uncurried-version functions are:
mapWithDefaultU
mapU
flatMapU
eqU
cmpU