implement Result.mapBoth and Result.map2 builtins

This commit is contained in:
Luke Boswell 2024-08-14 13:16:24 +10:00
parent 2dee5aea94
commit 7aebee8c94
No known key found for this signature in database
GPG key ID: F6DB3C9DB47377B0
3 changed files with 75 additions and 1 deletions

View file

@ -1,4 +1,15 @@
module [Result, isOk, isErr, map, mapErr, try, onErr, withDefault]
module [
Result,
isOk,
isErr,
map,
mapErr,
mapBoth,
map2,
try,
onErr,
withDefault,
]
import Bool exposing [Bool]
@ -67,6 +78,21 @@ mapErr = \result, transform ->
Ok v -> Ok v
Err e -> Err (transform e)
## Maps both the `Ok` and `Err` values of a `Result` to new values.
mapBoth : Result ok1 err1, (ok1 -> ok2), (err1 -> err2) -> Result ok2 err2
mapBoth = \result, okTransform, errTransform ->
result
|> Result.map okTransform
|> Result.mapErr errTransform
## Maps the `Ok` values of two `Result`s to a new value using a given transformation.
map2 : Result a err, Result b err, (a, b -> c) -> Result c err
map2 = \firstResult, secondResult, transform ->
when (firstResult, secondResult) is
(Ok first, Ok second) -> Ok (transform first second)
(Err err, _) -> Err err
(_, Err err) -> Err err
## If the result is `Ok`, transforms the entire result by running a conversion
## function on the value the `Ok` holds. Then returns that new result. If the
## result is `Err`, this has no effect. Use `onErr` to transform an `Err`.

View file

@ -1556,6 +1556,8 @@ define_builtins! {
5 RESULT_WITH_DEFAULT: "withDefault"
6 RESULT_TRY: "try"
7 RESULT_IS_OK: "isOk"
8 RESULT_MAP_BOTH: "mapBoth"
9 RESULT_MAP_TWO: "map2"
}
8 DICT: "Dict" => {
0 DICT_DICT: "Dict" exposed_type=true // the Dict.Dict type alias

View file

@ -354,3 +354,49 @@ fn roc_result_after_err() {
RocResult<RocStr, i64>
);
}
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
fn roc_result_map_other() {
assert_evals_to!(
indoc!(
r#"
result : Result I64 I64
result = Ok 42
result |> Result.mapBoth Num.toStr Num.toStr
"#
),
RocResult::ok(RocStr::from("42")),
RocResult<RocStr, RocStr>
);
assert_evals_to!(
indoc!(
r#"
result : Result I64 I64
result = Err 24
result |> Result.mapBoth Num.toStr Num.toStr
"#
),
RocResult::err(RocStr::from("24")),
RocResult<RocStr, RocStr>
);
assert_evals_to!(
indoc!(
r#"
first : Result I64 Str
first = Ok 24
second : Result I64 Str
second = Ok -10
Result.map2 first second \a, b -> a + b
"#
),
RocResult::ok(14i64),
RocResult<i64, RocStr>
);
}