diff --git a/.changeset/unlucky-berries-boil.md b/.changeset/unlucky-berries-boil.md new file mode 100644 index 000000000..f5fc2674f --- /dev/null +++ b/.changeset/unlucky-berries-boil.md @@ -0,0 +1,5 @@ +--- +"@fp-ts/core": patch +--- + +Option: change `firstSomeOf` signature diff --git a/Option.md b/Option.md index f14db0ff5..339a09093 100644 --- a/Option.md +++ b/Option.md @@ -333,6 +333,6 @@ console.log(output); // Output: Error: Cannot parse 'Not a number' as a number | `getOrUndefined` | `Option` | `A \| undefined` | | `orElse` | `Option`, `Option` | `Option` | | `orElseEither` | `Option`, `Option` | `Option>` | -| `firstSomeOf` | `Option`, `Iterable>` | `Option` | +| `firstSomeOf` | `Iterable>` | `Option` | | `getFailureSemigroup` | `Semigroup` | `Semigroup>` | | `getFailureMonoid` | `Monoid` | `Monoid>` | diff --git a/src/Option.ts b/src/Option.ts index 0758bdd68..2b2022462 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -15,7 +15,6 @@ import { constNull, constUndefined, pipe } from "@fp-ts/core/Function" import type { Kind, TypeLambda } from "@fp-ts/core/HKT" import * as either from "@fp-ts/core/internal/Either" import * as option from "@fp-ts/core/internal/Option" -import * as readonlyArray from "@fp-ts/core/internal/ReadonlyArray" import * as N from "@fp-ts/core/Number" import type { Predicate, Refinement } from "@fp-ts/core/Predicate" import type * as alternative from "@fp-ts/core/typeclass/Alternative" @@ -630,27 +629,18 @@ export const getFailureMonoid: (M: Monoid) => Monoid> = applicat Applicative ) -/** - * Given an Iterable collection of `Option`s, the function returns the first `Some` option found in the collection. - * - * @param collection - An iterable collection of `Option` to be searched - * - * @category error handling - * @since 1.0.0 - */ -export const firstSomeOf = (collection: Iterable>) => - (self: Option): Option => { - let out = self +const coproductMany = (self: Option, collection: Iterable>): Option => { + let out = self + if (isSome(out)) { + return out + } + for (out of collection) { if (isSome(out)) { return out } - for (out of collection) { - if (isSome(out)) { - return out - } - } - return out } + return out +} /** * @category instances @@ -659,7 +649,7 @@ export const firstSomeOf = (collection: Iterable>) => export const SemiCoproduct: semiCoproduct.SemiCoproduct = { ...Invariant, coproduct: (self, that) => isSome(self) ? self : that, - coproductMany: (self, collection) => pipe(self, firstSomeOf(collection)) + coproductMany } /** @@ -678,6 +668,24 @@ export const coproductEither = (that: Option) => (self: Option): Option> => isNone(self) ? pipe(that, map(either.right)) : pipe(self, map(either.left)) +/** + * Given an Iterable collection of `Option`s, the function returns the first `Some` option found in the collection. + * + * @param collection - An iterable collection of `Option` to be searched + * + * @category error handling + * @since 1.0.0 + */ +export const firstSomeOf = (collection: Iterable>): Option => { + let out: Option = none() + for (out of collection) { + if (isSome(out)) { + return out + } + } + return out +} + /** * @category instances * @since 1.0.0 @@ -685,12 +693,7 @@ export const coproductEither = (that: Option) => export const Coproduct: coproduct_.Coproduct = { ...SemiCoproduct, zero: none, - coproductAll: collection => { - const options = readonlyArray.fromIterable(collection) - return options.length > 0 ? - SemiCoproduct.coproductMany(options[0], options.slice(1)) : - option.none - } + coproductAll: firstSomeOf } /** diff --git a/test/Option.ts b/test/Option.ts index 4bafd76d6..0eacc6127 100644 --- a/test/Option.ts +++ b/test/Option.ts @@ -122,15 +122,30 @@ describe.concurrent("Option", () => { Util.deepStrictEqual(pipe(_.some(1), _.coproductEither(_.some("a"))), _.some(E.left(1))) }) + it("coproductMany", () => { + const coproductMany = _.SemiCoproduct.coproductMany + Util.deepStrictEqual(coproductMany(_.some(1), []), _.some(1)) + Util.deepStrictEqual(coproductMany(_.none(), []), _.none()) + Util.deepStrictEqual( + coproductMany(_.none(), [_.none(), _.none(), _.none(), _.some(1)]), + _.some(1) + ) + Util.deepStrictEqual( + coproductMany(_.none(), [_.none(), _.none(), _.none()]), + _.none() + ) + }) + it("firstSomeOf", () => { - Util.deepStrictEqual(pipe(_.some(1), _.firstSomeOf([])), _.some(1)) - Util.deepStrictEqual(pipe(_.none(), _.firstSomeOf([])), _.none()) + Util.deepStrictEqual(_.firstSomeOf([]), _.none()) + Util.deepStrictEqual(_.firstSomeOf([_.some(1)]), _.some(1)) + Util.deepStrictEqual(_.firstSomeOf([_.none()]), _.none()) Util.deepStrictEqual( - pipe(_.none(), _.firstSomeOf([_.none(), _.none(), _.none(), _.some(1)])), + _.firstSomeOf([_.none(), _.none(), _.none(), _.none(), _.some(1)]), _.some(1) ) Util.deepStrictEqual( - pipe(_.none(), _.firstSomeOf([_.none(), _.none(), _.none()])), + _.firstSomeOf([_.none(), _.none(), _.none(), _.none()]), _.none() ) })