diff --git a/CHANGELOG.md b/CHANGELOG.md index 5df9f6b0..f00c63a2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## Next version +### API changes + +- Add `Result.mapError` https://github.com/rescript-association/rescript-core/pull/98 + ## 0.4.0 ### API changes diff --git a/src/Core__Result.mjs b/src/Core__Result.mjs index b54c7671..101245ee 100644 --- a/src/Core__Result.mjs +++ b/src/Core__Result.mjs @@ -107,6 +107,17 @@ function forEach(r, f) { } +function mapError(r, f) { + if (r.TAG === /* Ok */0) { + return r; + } else { + return { + TAG: /* Error */1, + _0: Curry._1(f, r._0) + }; + } +} + export { getExn , mapWithDefault , @@ -118,5 +129,6 @@ export { equal , compare , forEach , + mapError , } /* No side effect */ diff --git a/src/Core__Result.res b/src/Core__Result.res index f0305e56..186f205f 100644 --- a/src/Core__Result.res +++ b/src/Core__Result.res @@ -93,3 +93,15 @@ let forEach = (r, f) => | Ok(ok) => f(ok) | Error(_) => () } + +// If the source result is Ok, should we return that instance, or +// create it again? In this implementation I'm returning that specific +// instance. However this is not consistent with the implementation for +// other functions like mapU and flatMapU, which recreate the result. +// This is more efficient. I'm not sure why the other implementations +// return a new instance. +let mapError = (r, f) => + switch r { + | Ok(_) as ok => ok + | Error(e) => Error(f(e)) + } diff --git a/src/Core__Result.resi b/src/Core__Result.resi index b82d1959..a8ab9bfc 100644 --- a/src/Core__Result.resi +++ b/src/Core__Result.resi @@ -209,3 +209,16 @@ Result.forEach(Error("x"), Console.log) // Does nothing, returns () ``` */ let forEach: (t<'a, 'b>, 'a => unit) => unit + +/** +`mapError(r, f)` generates a new `result` by applying the function `f` to the `Error` value. If the source is `Ok`, return it as-is. + +## Examples + +```rescript +let format = n => `Error code: ${n->Int.toString}` +mapError(Error(14), format) // Error("Error code: 14") +mapError(Ok("abc"), format) // Ok("abc") +``` +*/ +let mapError: (result<'a, 'b>, 'b => 'c) => result<'a, 'c> diff --git a/test/ResultTests.mjs b/test/ResultTests.mjs index 837ad952..d7f8245a 100644 --- a/test/ResultTests.mjs +++ b/test/ResultTests.mjs @@ -52,6 +52,42 @@ function forEachIfErrorDoNotCallFunction(param) { forEachIfErrorDoNotCallFunction(undefined); +Test.run([ + [ + "ResultTests.res", + 27, + 20, + 48 + ], + "mapError: if ok, return it" + ], Core__Result.mapError({ + TAG: /* Ok */0, + _0: 5 + }, (function (i) { + return Math.imul(i, 3); + })), eq, { + TAG: /* Ok */0, + _0: 5 + }); + +Test.run([ + [ + "ResultTests.res", + 30, + 13, + 42 + ], + "mapError: if error, apply f" + ], Core__Result.mapError({ + TAG: /* Error */1, + _0: 5 + }, (function (i) { + return Math.imul(i, 3); + })), eq, { + TAG: /* Error */1, + _0: 15 + }); + export { eq , forEachIfOkCallFunction , diff --git a/test/ResultTests.res b/test/ResultTests.res index 0dbda319..040028c6 100644 --- a/test/ResultTests.res +++ b/test/ResultTests.res @@ -19,3 +19,16 @@ let forEachIfErrorDoNotCallFunction = () => { Test.run(__POS_OF__("forEach: if error, do not call function"), called.contents, eq, []) } forEachIfErrorDoNotCallFunction() + +// ======== +// mapError +// ======== + +Test.run(__POS_OF__("mapError: if ok, return it"), Ok(5)->Result.mapError(i => i * 3), eq, Ok(5)) + +Test.run( + __POS_OF__("mapError: if error, apply f"), + Error(5)->Result.mapError(i => i * 3), + eq, + Error(15), +)