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
res1andres2are of the formOk(n)andOk(m), return the result off(n,m). - If one of
res1andres2are of the formError(e), returnfalse; iff bothres1andres2are 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
res1andres2are of the formOk(n)andOk(m), return the result off(n, m). - If
res1is of the formError(e)andres2of the formOk(n), return -1 (nothing is less than something). - If
res1is of the formOk(n)andres2of the formError(e), return 1 (something is greater than nothing). - If both
res1andres2are 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:
mapWithDefaultUmapUflatMapUeqUcmpU