From e300c0fdf63e7fa7bd58c1696494fa108e260ac4 Mon Sep 17 00:00:00 2001 From: glennsl Date: Sun, 19 Feb 2023 15:38:14 +0100 Subject: [PATCH 01/12] feat(option): add flat --- src/Core__Option.mjs | 8 ++++++++ src/Core__Option.res | 6 ++++++ src/Core__Option.resi | 12 ++++++++++++ 3 files changed, 26 insertions(+) diff --git a/src/Core__Option.mjs b/src/Core__Option.mjs index 29ad429b..d886ed3b 100644 --- a/src/Core__Option.mjs +++ b/src/Core__Option.mjs @@ -3,6 +3,13 @@ import * as Curry from "rescript/lib/es6/curry.js"; import * as Caml_option from "rescript/lib/es6/caml_option.js"; +function flat(opt) { + if (opt !== undefined) { + return Caml_option.valFromOption(opt); + } + +} + function filter(opt, p) { var p$1 = Curry.__1(p); if (opt !== undefined && p$1(Caml_option.valFromOption(opt))) { @@ -107,6 +114,7 @@ function cmp(a, b, f) { } export { + flat , filter , forEach , getExn , diff --git a/src/Core__Option.res b/src/Core__Option.res index 9b688647..2dcb2922 100644 --- a/src/Core__Option.res +++ b/src/Core__Option.res @@ -22,6 +22,12 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +let flat = opt => + switch opt { + | Some(v) => v + | None => None + } + let filterU = (opt, p) => switch opt { | Some(x) as some if p(. x) => some diff --git a/src/Core__Option.resi b/src/Core__Option.resi index fb3c8a46..e4ef6870 100644 --- a/src/Core__Option.resi +++ b/src/Core__Option.resi @@ -39,6 +39,18 @@ let someString: option = Some("hello") ``` */ +/** +`flat(value)` flattens a nested `option` value to a single level.. + +## Examples + +```rescript +Option.float(Some(Some(10))) // Some(10) +Option.flat(Some(None)) // None +``` +*/ +let flat: option> => option<'a> + /** `filter(opt, f)` applies `f` to `opt`, if `f` returns `true`, then it returns `Some(value)`, otherwise returns `None`. From 2c1d16b3e972254e0ca44c854eeb8a6058e15fe5 Mon Sep 17 00:00:00 2001 From: glennsl Date: Sun, 19 Feb 2023 15:52:33 +0100 Subject: [PATCH 02/12] feat(option): add expect --- src/Core__Option.mjs | 12 ++++++++++++ src/Core__Option.res | 6 ++++++ src/Core__Option.resi | 14 ++++++++++++++ 3 files changed, 32 insertions(+) diff --git a/src/Core__Option.mjs b/src/Core__Option.mjs index d886ed3b..4a036610 100644 --- a/src/Core__Option.mjs +++ b/src/Core__Option.mjs @@ -36,6 +36,17 @@ function getExn(x) { }; } +function expect(opt, message) { + if (opt !== undefined) { + return Caml_option.valFromOption(opt); + } + throw { + RE_EXN_ID: "Failure", + _1: message, + Error: new Error() + }; +} + function mapWithDefault(opt, $$default, f) { var f$1 = Curry.__1(f); if (opt !== undefined) { @@ -118,6 +129,7 @@ export { filter , forEach , getExn , + expect , mapWithDefault , map , flatMap , diff --git a/src/Core__Option.res b/src/Core__Option.res index 2dcb2922..90d03a41 100644 --- a/src/Core__Option.res +++ b/src/Core__Option.res @@ -50,6 +50,12 @@ let getExn = x => | None => raise(Not_found) } +let expect = (opt, message) => + switch opt { + | Some(value) => value + | None => raise(Failure(message)) + } + external getUnsafe: option<'a> => 'a = "%identity" let mapWithDefaultU = (opt, default, f) => diff --git a/src/Core__Option.resi b/src/Core__Option.resi index e4ef6870..1e5bf6e8 100644 --- a/src/Core__Option.resi +++ b/src/Core__Option.resi @@ -91,6 +91,20 @@ Option.getExn(None) /* Raises an Error */ */ let getExn: option<'a> => 'a +/** +`expect(opt, message)` returns `value` if `Some(value)`, raises a `Failure` expection with the given message if `None`. + +```rescript +Option.expect(Some(3), "should not be None") // 3 +Option.expect(None, "should not be None") // Raises `Failure("should not be None")` +``` + +## Exceptions + +- Raises `Failure` if `opt` is `None` +*/ +let expect: (option<'a>, string) => 'a + /** `getUnsafe(value)` returns `value`. From 90483c888901bbc37274fb37732e91e8f9b6ae99 Mon Sep 17 00:00:00 2001 From: glennsl Date: Sun, 19 Feb 2023 15:53:36 +0100 Subject: [PATCH 03/12] refactor(option): consistent variable naming in implementation --- src/Core__Option.mjs | 14 +++++++------- src/Core__Option.res | 34 +++++++++++++++++----------------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/Core__Option.mjs b/src/Core__Option.mjs index 4a036610..149726db 100644 --- a/src/Core__Option.mjs +++ b/src/Core__Option.mjs @@ -26,9 +26,9 @@ function forEach(opt, f) { } -function getExn(x) { - if (x !== undefined) { - return Caml_option.valFromOption(x); +function getExn(opt) { + if (opt !== undefined) { + return Caml_option.valFromOption(opt); } throw { RE_EXN_ID: "Not_found", @@ -88,12 +88,12 @@ function orElse(opt, other) { } } -function isSome(x) { - return x !== undefined; +function isSome(opt) { + return opt !== undefined; } -function isNone(x) { - return x === undefined; +function isNone(value) { + return value === undefined; } function eq(a, b, f) { diff --git a/src/Core__Option.res b/src/Core__Option.res index 90d03a41..948e4bfd 100644 --- a/src/Core__Option.res +++ b/src/Core__Option.res @@ -30,23 +30,23 @@ let flat = opt => let filterU = (opt, p) => switch opt { - | Some(x) as some if p(. x) => some + | Some(value) as some if p(. value) => some | _ => None } -let filter = (opt, p) => filterU(opt, (. x) => p(x)) +let filter = (opt, p) => filterU(opt, (. value) => p(value)) let forEachU = (opt, f) => switch opt { - | Some(x) => f(. x) + | Some(value) => f(. value) | None => () } -let forEach = (opt, f) => forEachU(opt, (. x) => f(x)) +let forEach = (opt, f) => forEachU(opt, (. value) => f(value)) -let getExn = x => - switch x { - | Some(x) => x +let getExn = opt => + switch opt { + | Some(value) => value | None => raise(Not_found) } @@ -60,31 +60,31 @@ external getUnsafe: option<'a> => 'a = "%identity" let mapWithDefaultU = (opt, default, f) => switch opt { - | Some(x) => f(. x) + | Some(value) => f(. value) | None => default } -let mapWithDefault = (opt, default, f) => mapWithDefaultU(opt, default, (. x) => f(x)) +let mapWithDefault = (opt, default, f) => mapWithDefaultU(opt, default, (. value) => f(value)) let mapU = (opt, f) => switch opt { - | Some(x) => Some(f(. x)) + | Some(value) => Some(f(. value)) | None => None } -let map = (opt, f) => mapU(opt, (. x) => f(x)) +let map = (opt, f) => mapU(opt, (. value) => f(value)) let flatMapU = (opt, f) => switch opt { - | Some(x) => f(. x) + | Some(value) => f(. value) | None => None } -let flatMap = (opt, f) => flatMapU(opt, (. x) => f(x)) +let flatMap = (opt, f) => flatMapU(opt, (. value) => f(value)) let getWithDefault = (opt, default) => switch opt { - | Some(x) => x + | Some(value) => value | None => default } @@ -94,13 +94,13 @@ let orElse = (opt, other) => | None => other } -let isSome = x => - switch x { +let isSome = opt => + switch opt { | Some(_) => true | None => false } -let isNone = x => x == None +let isNone = value => value == None let eqU = (a, b, f) => switch a { From f61e47e0296d11b73d40a2c6f005d0f35a1d2f5b Mon Sep 17 00:00:00 2001 From: glennsl Date: Sun, 19 Feb 2023 16:00:53 +0100 Subject: [PATCH 04/12] docs(option/getExn): more specific description --- src/Core__Option.resi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Core__Option.resi b/src/Core__Option.resi index 1e5bf6e8..723ecb33 100644 --- a/src/Core__Option.resi +++ b/src/Core__Option.resi @@ -78,7 +78,7 @@ Option.forEach(None, x => Console.log(x)) // returns () let forEach: (option<'a>, 'a => unit) => unit /** -`getExn(opt)` returns `value` if `opt` is `Some(value)`, otherwise raises an exception. +`getExn(opt)` returns `value` if `opt` is `Some(value)`, raises `Not_found` if `None`. ```rescript Option.getExn(Some(3)) // 3 @@ -87,7 +87,7 @@ Option.getExn(None) /* Raises an Error */ ## Exceptions -- Raises an error if `opt` is `None` +- Raises `Not_found` if `opt` is `None` */ let getExn: option<'a> => 'a From 79c80868b70ea0c06f6ae9369d4c5afef51f5e31 Mon Sep 17 00:00:00 2001 From: glennsl Date: Sun, 19 Feb 2023 16:01:59 +0100 Subject: [PATCH 05/12] docs(option/getUnsafe): more precise description of unsafe --- src/Core__Option.resi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Core__Option.resi b/src/Core__Option.resi index 723ecb33..ee47474d 100644 --- a/src/Core__Option.resi +++ b/src/Core__Option.resi @@ -115,9 +115,9 @@ Option.getUnsafe(Some(3)) == 3 Option.getUnsafe(None) // Raises an error ``` -## Exceptions +## Improtant -- This is an unsafe operation, it assumes `value` is neither `None` nor `Some(None(...)))` +This is an unsafe operation, it assumes `value` is neither `None`, `Some(None))`, `Some(Some(None))` etc. */ external getUnsafe: option<'a> => 'a = "%identity" From be9897ed5d2a0376820501b024de5d30edf69650 Mon Sep 17 00:00:00 2001 From: glennsl Date: Sun, 19 Feb 2023 16:09:20 +0100 Subject: [PATCH 06/12] feat(option): add or as replacement for orElse, deprecate orElse --- src/Core__Option.mjs | 5 ++++- src/Core__Option.res | 5 +++-- src/Core__Option.resi | 14 ++++++++++++++ 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/Core__Option.mjs b/src/Core__Option.mjs index 149726db..58088a4d 100644 --- a/src/Core__Option.mjs +++ b/src/Core__Option.mjs @@ -80,7 +80,7 @@ function getWithDefault(opt, $$default) { } } -function orElse(opt, other) { +function or(opt, other) { if (opt !== undefined) { return opt; } else { @@ -124,6 +124,8 @@ function cmp(a, b, f) { } } +var orElse = or; + export { flat , filter , @@ -134,6 +136,7 @@ export { map , flatMap , getWithDefault , + or , orElse , isSome , isNone , diff --git a/src/Core__Option.res b/src/Core__Option.res index 948e4bfd..c1b9ffdc 100644 --- a/src/Core__Option.res +++ b/src/Core__Option.res @@ -88,9 +88,9 @@ let getWithDefault = (opt, default) => | None => default } -let orElse = (opt, other) => +let or = (opt, other) => switch opt { - | Some(_) as some => some + | Some(_) => opt | None => other } @@ -99,6 +99,7 @@ let isSome = opt => | Some(_) => true | None => false } +let orElse = or let isNone = value => value == None diff --git a/src/Core__Option.resi b/src/Core__Option.resi index ee47474d..3c15aa0e 100644 --- a/src/Core__Option.resi +++ b/src/Core__Option.resi @@ -186,6 +186,19 @@ None->greet // "Greetings Anonymous" */ let getWithDefault: (option<'a>, 'a) => 'a +/** +`or(opt1, opt2)` returns `opt2` if `opt1` is `None`, otherwise `opt1`. + +## Examples + +```rescript +Option.or(Some(1812), Some(1066)) == Some(1812) +Option.or(None, Some(1066) == Some(1066) +Option.or(None, None) == None +``` +*/ +let or: (option<'a>, option<'a>) => option<'a> + /** `orElse(opt1, opt2)` returns `opt2` if `opt1` is `None`, otherwise `opt1`. @@ -197,6 +210,7 @@ Option.orElse(None, Some(1066) == Some(1066) Option.orElse(None, None) == None ``` */ +@deprecated let orElse: (option<'a>, option<'a>) => option<'a> /** From de8a86ffb78e368ee69e387b6feb6766e8e03d97 Mon Sep 17 00:00:00 2001 From: glennsl Date: Sun, 19 Feb 2023 16:10:11 +0100 Subject: [PATCH 07/12] refactor(option): simplify implementation of isSome --- src/Core__Option.mjs | 4 ++-- src/Core__Option.res | 9 +++------ 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/Core__Option.mjs b/src/Core__Option.mjs index 58088a4d..0b922916 100644 --- a/src/Core__Option.mjs +++ b/src/Core__Option.mjs @@ -92,8 +92,8 @@ function isSome(opt) { return opt !== undefined; } -function isNone(value) { - return value === undefined; +function isNone(opt) { + return opt === undefined; } function eq(a, b, f) { diff --git a/src/Core__Option.res b/src/Core__Option.res index c1b9ffdc..9d264bc6 100644 --- a/src/Core__Option.res +++ b/src/Core__Option.res @@ -94,14 +94,11 @@ let or = (opt, other) => | None => other } -let isSome = opt => - switch opt { - | Some(_) => true - | None => false - } let orElse = or -let isNone = value => value == None +let isSome = opt => opt !== None + +let isNone = opt => opt == None let eqU = (a, b, f) => switch a { From 5c0644055b9783f1f48ada4dc8c4c8d0985d266d Mon Sep 17 00:00:00 2001 From: glennsl Date: Thu, 2 Mar 2023 10:53:35 +0100 Subject: [PATCH 08/12] docs: update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e8490e2..9e3d3801 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ - Add `panic`/`Error.panic`. https://github.com/rescript-association/rescript-core/pull/72 - The globally available `null` value now originates from `Nullable` and not `Null`, just like the globally available `undefined` value does. https://github.com/rescript-association/rescript-core/pull/88 - Add `Int.range` and `Int.rangeWithOptions`, https://github.com/rescript-association/rescript-core/pull/52 +- Add `flat`, `expect`, and `or` to `Option`, deprecate `orElse`. https://github.com/rescript-association/rescript-core/pull/57 ### Documentation From a056cd0e870fb23dd7d66c97668cf92196deefd5 Mon Sep 17 00:00:00 2001 From: Glenn Slotte Date: Sun, 19 Feb 2023 19:12:01 +0100 Subject: [PATCH 09/12] docs(option): fix embarassing typos Co-authored-by: Christoph Knittel --- src/Core__Option.resi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Core__Option.resi b/src/Core__Option.resi index 3c15aa0e..84c7cf21 100644 --- a/src/Core__Option.resi +++ b/src/Core__Option.resi @@ -40,7 +40,7 @@ let someString: option = Some("hello") */ /** -`flat(value)` flattens a nested `option` value to a single level.. +`flat(value)` flattens a nested `option` value to a single level. ## Examples @@ -115,7 +115,7 @@ Option.getUnsafe(Some(3)) == 3 Option.getUnsafe(None) // Raises an error ``` -## Improtant +## Important This is an unsafe operation, it assumes `value` is neither `None`, `Some(None))`, `Some(Some(None))` etc. */ From 29b3d5d65533a3532a65a6b188d53871ef50328c Mon Sep 17 00:00:00 2001 From: Glenn Slotte Date: Mon, 20 Feb 2023 20:02:45 +0100 Subject: [PATCH 10/12] docs(option/orElse): add deprecation message Co-authored-by: Pedro Castro --- src/Core__Option.resi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Core__Option.resi b/src/Core__Option.resi index 84c7cf21..468a77c5 100644 --- a/src/Core__Option.resi +++ b/src/Core__Option.resi @@ -210,7 +210,7 @@ Option.orElse(None, Some(1066) == Some(1066) Option.orElse(None, None) == None ``` */ -@deprecated +@deprecated("Use `or` instead") let orElse: (option<'a>, option<'a>) => option<'a> /** From 8b198d50b825352b86d0772cc5e11267775b069c Mon Sep 17 00:00:00 2001 From: Glenn Slotte Date: Mon, 20 Feb 2023 20:03:21 +0100 Subject: [PATCH 11/12] docs(option/flat): flat is not float Co-authored-by: Pedro Castro --- src/Core__Option.resi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Core__Option.resi b/src/Core__Option.resi index 468a77c5..5a9a009b 100644 --- a/src/Core__Option.resi +++ b/src/Core__Option.resi @@ -45,7 +45,7 @@ let someString: option = Some("hello") ## Examples ```rescript -Option.float(Some(Some(10))) // Some(10) +Option.flat(Some(Some(10))) // Some(10) Option.flat(Some(None)) // None ``` */ From 9280051282163546cbea1130cbd6b0c37083666c Mon Sep 17 00:00:00 2001 From: glennsl Date: Thu, 2 Mar 2023 11:02:18 +0100 Subject: [PATCH 12/12] feat(error/expect): use panic instead of raising Failure --- src/Core__Option.mjs | 8 +++----- src/Core__Option.res | 2 +- src/Core__Option.resi | 2 +- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/Core__Option.mjs b/src/Core__Option.mjs index 0b922916..d0679d4c 100644 --- a/src/Core__Option.mjs +++ b/src/Core__Option.mjs @@ -2,6 +2,7 @@ import * as Curry from "rescript/lib/es6/curry.js"; import * as Caml_option from "rescript/lib/es6/caml_option.js"; +import * as Core__Error from "./Core__Error.mjs"; function flat(opt) { if (opt !== undefined) { @@ -39,12 +40,9 @@ function getExn(opt) { function expect(opt, message) { if (opt !== undefined) { return Caml_option.valFromOption(opt); + } else { + return Core__Error.panic(message); } - throw { - RE_EXN_ID: "Failure", - _1: message, - Error: new Error() - }; } function mapWithDefault(opt, $$default, f) { diff --git a/src/Core__Option.res b/src/Core__Option.res index 9d264bc6..726a074f 100644 --- a/src/Core__Option.res +++ b/src/Core__Option.res @@ -53,7 +53,7 @@ let getExn = opt => let expect = (opt, message) => switch opt { | Some(value) => value - | None => raise(Failure(message)) + | None => Core__Error.panic(message) } external getUnsafe: option<'a> => 'a = "%identity" diff --git a/src/Core__Option.resi b/src/Core__Option.resi index 5a9a009b..2c1f2025 100644 --- a/src/Core__Option.resi +++ b/src/Core__Option.resi @@ -101,7 +101,7 @@ Option.expect(None, "should not be None") // Raises `Failure("should not be None ## Exceptions -- Raises `Failure` if `opt` is `None` +- Panics if `opt` is `None` */ let expect: (option<'a>, string) => 'a