From 07796813f07de035719728733096ba64ce333469 Mon Sep 17 00:00:00 2001 From: Maxim Khramtsov Date: Thu, 26 Sep 2024 13:02:28 +0200 Subject: [PATCH] `Effect.mapAccum` & `Array.mapAccum` preserve non-emptiness (#3675) Co-authored-by: maksim.khramtsov --- .changeset/healthy-dogs-judge.md | 5 +++++ packages/effect/dtslint/Array.ts | 21 +++++++++++++++++ packages/effect/dtslint/Effect.ts | 25 +++++++++++++++++++++ packages/effect/src/Array.ts | 12 ++++++---- packages/effect/src/Effect.ts | 14 ++++++------ packages/effect/src/internal/core-effect.ts | 14 ++++++------ 6 files changed, 73 insertions(+), 18 deletions(-) create mode 100644 .changeset/healthy-dogs-judge.md diff --git a/.changeset/healthy-dogs-judge.md b/.changeset/healthy-dogs-judge.md new file mode 100644 index 0000000000..60164c55f0 --- /dev/null +++ b/.changeset/healthy-dogs-judge.md @@ -0,0 +1,5 @@ +--- +"effect": minor +--- + +Effect.mapAccum & Array.mapAccum preserve non-emptiness diff --git a/packages/effect/dtslint/Array.ts b/packages/effect/dtslint/Array.ts index 53ea255d1c..682abf120d 100644 --- a/packages/effect/dtslint/Array.ts +++ b/packages/effect/dtslint/Array.ts @@ -1504,3 +1504,24 @@ pipe( _n // $ExpectType 1 | 2 ) => "a" as const) ) + +// ------------------------------------------------------------------------------------- +// mapAccum +// ------------------------------------------------------------------------------------- + +// $ExpectType [state: number, mappedArray: string[]] +Array.mapAccum(strings, 0, (s, a, i) => [s + i, a]) + +// $ExpectType [state: number, mappedArray: [string, ...string[]]] +Array.mapAccum(nonEmptyReadonlyStrings, 0, (s, a, i) => [s + i, a]) + +// $ExpectType [state: number, mappedArray: string[]] +pipe( + strings, + Array.mapAccum(0, (s, a, i) => [s + i, a]) +) +// $ExpectType [state: number, mappedArray: [string, ...string[]]] +pipe( + nonEmptyReadonlyStrings, + Array.mapAccum(0, (s, a, i) => [s + i, a]) +) diff --git a/packages/effect/dtslint/Effect.ts b/packages/effect/dtslint/Effect.ts index caeaea1b59..27e1f45659 100644 --- a/packages/effect/dtslint/Effect.ts +++ b/packages/effect/dtslint/Effect.ts @@ -1263,3 +1263,28 @@ pipe( ) => "b" as const ) ) + +// ------------------------------------------------------------------------------------- +// mapAccum +// ------------------------------------------------------------------------------------- + +declare const nonEmptyReadonlyStrings: NonEmptyReadonlyArray +declare const strings: Array + +// $ExpectType Effect<[number, string[]], never, never> +Effect.mapAccum(strings, 0, (s, a, i) => Effect.succeed([s + i, a])) + +// $ExpectType Effect<[number, [string, ...string[]]], never, never> +Effect.mapAccum(nonEmptyReadonlyStrings, 0, (s, a, i) => Effect.succeed([s + i, a])) + +// $ExpectType Effect<[number, string[]], never, never> +pipe( + strings, + Effect.mapAccum(0, (s, a, i) => Effect.succeed([s + i, a])) +) + +// $ExpectType Effect<[number, [string, ...string[]]], never, never> +pipe( + nonEmptyReadonlyStrings, + Effect.mapAccum(0, (s, a, i) => Effect.succeed([s + i, a])) +) diff --git a/packages/effect/src/Array.ts b/packages/effect/src/Array.ts index 6867785277..334cbbfb19 100644 --- a/packages/effect/src/Array.ts +++ b/packages/effect/src/Array.ts @@ -2859,11 +2859,15 @@ export const join: { * @category folding */ export const mapAccum: { - ( + = Iterable>( s: S, - f: (s: S, a: A, i: number) => readonly [S, B] - ): (self: Iterable) => [state: S, mappedArray: Array] - (self: Iterable, s: S, f: (s: S, a: A, i: number) => readonly [S, B]): [state: S, mappedArray: Array] + f: (s: S, a: ReadonlyArray.Infer, i: number) => readonly [S, B] + ): (self: I) => [state: S, mappedArray: ReadonlyArray.With] + = Iterable>( + self: I, + s: S, + f: (s: S, a: ReadonlyArray.Infer, i: number) => readonly [S, B] + ): [state: S, mappedArray: ReadonlyArray.With] } = dual( 3, (self: Iterable, s: S, f: (s: S, a: A, i: number) => [S, B]): [state: S, mappedArray: Array] => { diff --git a/packages/effect/src/Effect.ts b/packages/effect/src/Effect.ts index 2a2f95508b..f9929c4312 100644 --- a/packages/effect/src/Effect.ts +++ b/packages/effect/src/Effect.ts @@ -2365,15 +2365,15 @@ export const map: { * @category mapping */ export const mapAccum: { - ( + = Iterable>( zero: S, - f: (s: S, a: A, i: number) => Effect - ): (elements: Iterable) => Effect<[S, Array], E, R> - ( - elements: Iterable, + f: (s: S, a: RA.ReadonlyArray.Infer, i: number) => Effect + ): (elements: I) => Effect<[S, RA.ReadonlyArray.With], E, R> + = Iterable>( + elements: I, zero: S, - f: (s: S, a: A, i: number) => Effect - ): Effect<[S, Array], E, R> + f: (s: S, a: RA.ReadonlyArray.Infer, i: number) => Effect + ): Effect<[S, RA.ReadonlyArray.With], E, R> } = effect.mapAccum /** diff --git a/packages/effect/src/internal/core-effect.ts b/packages/effect/src/internal/core-effect.ts index 8dfc44b07d..5d3c929fc4 100644 --- a/packages/effect/src/internal/core-effect.ts +++ b/packages/effect/src/internal/core-effect.ts @@ -1055,17 +1055,17 @@ const loopDiscard = ( /* @internal */ export const mapAccum: { - ( + = Iterable>( zero: S, f: (s: S, a: A, i: number) => Effect.Effect - ): (elements: Iterable) => Effect.Effect<[S, Array], E, R> - ( - elements: Iterable, + ): (elements: I) => Effect.Effect<[S, Arr.ReadonlyArray.With], E, R> + = Iterable>( + elements: I, zero: S, f: (s: S, a: A, i: number) => Effect.Effect - ): Effect.Effect<[S, Array], E, R> -} = dual(3, ( - elements: Iterable, + ): Effect.Effect<[S, Arr.ReadonlyArray.With], E, R> +} = dual(3, = Iterable>( + elements: I, zero: S, f: (s: S, a: A, i: number) => Effect.Effect ): Effect.Effect<[S, Array], E, R> =>