From 6efe63cca0b072502f91810e6c97fcb6135e3d2e Mon Sep 17 00:00:00 2001 From: Chris Wilkinson Date: Thu, 3 Mar 2022 10:20:00 +0000 Subject: [PATCH] Add intercalate to arrays --- docs/modules/Array.ts.md | 23 +++++++++++++++++++++++ docs/modules/NonEmptyArray.ts.md | 22 ++++++++++++++++++++++ docs/modules/ReadonlyArray.ts.md | 24 +++++++++++++++++++++++- docs/modules/ReadonlyNonEmptyArray.ts.md | 22 ++++++++++++++++++++++ src/Array.ts | 15 +++++++++++++++ src/NonEmptyArray.ts | 14 ++++++++++++++ src/ReadonlyArray.ts | 18 +++++++++++++++++- src/ReadonlyNonEmptyArray.ts | 16 ++++++++++++++++ test/Array.ts | 9 +++++++++ test/NonEmptyArray.ts | 8 ++++++++ test/ReadonlyArray.ts | 9 +++++++++ test/ReadonlyNonEmptyArray.ts | 8 ++++++++ 12 files changed, 186 insertions(+), 2 deletions(-) diff --git a/docs/modules/Array.ts.md b/docs/modules/Array.ts.md index ba903881e..d3d30babe 100644 --- a/docs/modules/Array.ts.md +++ b/docs/modules/Array.ts.md @@ -87,6 +87,7 @@ Added in v2.0.0 - [flatten](#flatten) - [fromEitherK](#fromeitherk) - [fromOptionK](#fromoptionk) + - [intercalate](#intercalate) - [intersection](#intersection) - [intersperse](#intersperse) - [lefts](#lefts) @@ -1436,6 +1437,28 @@ export declare const fromOptionK: (f: (...a: A) Added in v2.11.0 +## intercalate + +Creates a new `Array` placing an element in between members of the input `Array`, then folds the results using the +provided `Monoid`. + +**Signature** + +```ts +export declare const intercalate: (M: Monoid) => (sep: A) => (as: A[]) => A +``` + +**Example** + +```ts +import * as S from 'fp-ts/string' +import { intercalate } from 'fp-ts/Array' + +assert.deepStrictEqual(intercalate(S.Monoid)('-')(['a', 'b', 'c']), 'a-b-c') +``` + +Added in v2.11.9 + ## intersection Creates an array of unique values that are included in all given arrays using a `Eq` for equality diff --git a/docs/modules/NonEmptyArray.ts.md b/docs/modules/NonEmptyArray.ts.md index 4c96c220b..0c03172b5 100644 --- a/docs/modules/NonEmptyArray.ts.md +++ b/docs/modules/NonEmptyArray.ts.md @@ -63,6 +63,7 @@ Added in v2.0.0 - [group](#group) - [groupBy](#groupby) - [insertAt](#insertat) + - [intercalate](#intercalate) - [intersperse](#intersperse) - [modifyAt](#modifyat) - [prependAll](#prependall) @@ -531,6 +532,27 @@ export declare const insertAt: (i: number, a: A) => (as: A[]) => Option(S: Se.Semigroup) => (sep: A) => (as: NonEmptyArray) => A +``` + +**Example** + +```ts +import * as S from 'fp-ts/string' +import { intercalate } from 'fp-ts/NonEmptyArray' + +assert.deepStrictEqual(intercalate(S.Semigroup)('-')(['a', 'b', 'c']), 'a-b-c') +``` + +Added in v2.11.9 + ## intersperse Places an element in between members of an array diff --git a/docs/modules/ReadonlyArray.ts.md b/docs/modules/ReadonlyArray.ts.md index bec84cfcd..632271b8a 100644 --- a/docs/modules/ReadonlyArray.ts.md +++ b/docs/modules/ReadonlyArray.ts.md @@ -82,6 +82,7 @@ Added in v2.5.0 - [flatten](#flatten) - [fromEitherK](#fromeitherk) - [fromOptionK](#fromoptionk) + - [intercalate](#intercalate) - [intersection](#intersection) - [intersperse](#intersperse) - [lefts](#lefts) @@ -970,6 +971,27 @@ export declare const fromOptionK: ( Added in v2.11.0 +## intercalate + +Places an element in between members of an array`, then folds the results using the provided `Monoid`. + +**Signature** + +```ts +export declare const intercalate: (M: Monoid) => (sep: A) => (as: readonly A[]) => A +``` + +**Example** + +```ts +import * as S from 'fp-ts/string' +import { intercalate } from 'fp-ts/Array' + +assert.deepStrictEqual(intercalate(S.Monoid)('-')(['a', 'b', 'c']), 'a-b-c') +``` + +Added in v2.11.9 + ## intersection Creates an array of unique values that are included in all given arrays using a `Eq` for equality @@ -1901,7 +1923,7 @@ Added in v2.7.0 **Signature** ```ts -export declare const Foldable: Foldable1<'ReadonlyArray'> +export declare const Foldable: F.Foldable1<'ReadonlyArray'> ``` Added in v2.7.0 diff --git a/docs/modules/ReadonlyNonEmptyArray.ts.md b/docs/modules/ReadonlyNonEmptyArray.ts.md index 7b746916d..14704517a 100644 --- a/docs/modules/ReadonlyNonEmptyArray.ts.md +++ b/docs/modules/ReadonlyNonEmptyArray.ts.md @@ -68,6 +68,7 @@ Added in v2.5.0 - [getUnionSemigroup](#getunionsemigroup) - [group](#group) - [groupBy](#groupby) + - [intercalate](#intercalate) - [intersperse](#intersperse) - [modifyAt](#modifyat) - [prependAll](#prependall) @@ -607,6 +608,27 @@ assert.deepStrictEqual(groupBy((s: string) => String(s.length))(['a', 'b', 'ab'] Added in v2.5.0 +## intercalate + +**Note**. The constraint is relaxed: a `Semigroup` instead of a `Monoid`. + +**Signature** + +```ts +export declare const intercalate: (S: Se.Semigroup) => (sep: A) => (as: ReadonlyNonEmptyArray) => A +``` + +**Example** + +```ts +import * as S from 'fp-ts/string' +import { intercalate } from 'fp-ts/ReadonlyNonEmptyArray' + +assert.deepStrictEqual(intercalate(S.Semigroup)('-')(['a', 'b', 'c']), 'a-b-c') +``` + +Added in v2.11.9 + ## intersperse Places an element in between members of a `ReadonlyNonEmptyArray`. diff --git a/src/Array.ts b/src/Array.ts index 919043e5d..d1e9c2d45 100644 --- a/src/Array.ts +++ b/src/Array.ts @@ -1124,6 +1124,21 @@ export const intersperse = (middle: A): ((as: Array) => Array) => { return (as) => (isNonEmpty(as) ? f(as) : copy(as)) } +/** + * Creates a new `Array` placing an element in between members of the input `Array`, then folds the results using the + * provided `Monoid`. + * + * @example + * import * as S from 'fp-ts/string' + * import { intercalate } from 'fp-ts/Array' + * + * assert.deepStrictEqual(intercalate(S.Monoid)('-')(['a', 'b', 'c']), 'a-b-c') + * + * @category combinators + * @since 2.11.9 + */ +export const intercalate: (M: Monoid) => (sep: A) => (as: Array) => A = RA.intercalate + /** * Creates a new `Array` rotating the input `Array` by `n` steps. * diff --git a/src/NonEmptyArray.ts b/src/NonEmptyArray.ts index 1af51e4bb..ec5b9d815 100644 --- a/src/NonEmptyArray.ts +++ b/src/NonEmptyArray.ts @@ -551,6 +551,20 @@ export const intersperse = (middle: A) => (as: NonEmptyArray): NonEmptyArr return isNonEmpty(rest) ? pipe(rest, prependAll(middle), prepend(head(as))) : copy(as) } +/** + * **Note**. The constraint is relaxed: a `Semigroup` instead of a `Monoid`. + * + * @example + * import * as S from 'fp-ts/string' + * import { intercalate } from 'fp-ts/NonEmptyArray' + * + * assert.deepStrictEqual(intercalate(S.Semigroup)('-')(['a', 'b', 'c']), 'a-b-c') + * + * @category combinators + * @since 2.11.9 + */ +export const intercalate: (S: Semigroup) => (sep: A) => (as: NonEmptyArray) => A = RNEA.intercalate + /** * @category combinators * @since 2.0.0 diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index 3a06c93cd..efd7fb8cb 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -13,7 +13,7 @@ import { Eq, fromEquals } from './Eq' import { Extend1 } from './Extend' import { Filterable1 } from './Filterable' import { FilterableWithIndex1, PredicateWithIndex, RefinementWithIndex } from './FilterableWithIndex' -import { Foldable1 } from './Foldable' +import * as F from './Foldable' import { FoldableWithIndex1 } from './FoldableWithIndex' import { FromEither1, fromEitherK as fromEitherK_ } from './FromEither' import { identity, Lazy, pipe } from './function' @@ -49,6 +49,7 @@ import { } from './Witherable' import { Zero1, guard as guard_ } from './Zero' +import Foldable1 = F.Foldable1 import ReadonlyNonEmptyArray = RNEA.ReadonlyNonEmptyArray // ------------------------------------------------------------------------------------- @@ -1012,6 +1013,21 @@ export const intersperse = (middle: A): ((as: ReadonlyArray) => ReadonlyAr return (as) => (isNonEmpty(as) ? f(as) : as) } +/** + * Places an element in between members of an array`, then folds the results using the provided `Monoid`. + * + * @example + * import * as S from 'fp-ts/string' + * import { intercalate } from 'fp-ts/Array' + * + * assert.deepStrictEqual(intercalate(S.Monoid)('-')(['a', 'b', 'c']), 'a-b-c') + * + * @category combinators + * @since 2.11.9 + */ +export const intercalate: (M: Monoid) => (sep: A) => (as: ReadonlyArray) => A = (M) => (sep) => (as) => + F.intercalate(M, Foldable)(sep, as) + /** * Rotate a `ReadonlyArray` by `n` steps. * diff --git a/src/ReadonlyNonEmptyArray.ts b/src/ReadonlyNonEmptyArray.ts index 13ea6051f..a2d7d6635 100644 --- a/src/ReadonlyNonEmptyArray.ts +++ b/src/ReadonlyNonEmptyArray.ts @@ -566,6 +566,22 @@ export const intersperse = (middle: A) => (as: ReadonlyNonEmptyArray): Rea return isNonEmpty(rest) ? pipe(rest, prependAll(middle), prepend(head(as))) : as } +/** + * **Note**. The constraint is relaxed: a `Semigroup` instead of a `Monoid`. + * + * @example + * import * as S from 'fp-ts/string' + * import { intercalate } from 'fp-ts/ReadonlyNonEmptyArray' + * + * assert.deepStrictEqual(intercalate(S.Semigroup)('-')(['a', 'b', 'c']), 'a-b-c') + * + * @category combinators + * @since 2.11.9 + */ +export const intercalate: (S: Semigroup) => (sep: A) => (as: ReadonlyNonEmptyArray) => A = (S) => (sep) => ( + as +) => concatAll(S)(intersperse(sep)(as)) + /** * @category combinators * @since 2.10.0 diff --git a/test/Array.ts b/test/Array.ts index bb01e10ef..8c96f65a2 100644 --- a/test/Array.ts +++ b/test/Array.ts @@ -702,6 +702,15 @@ describe('Array', () => { U.deepStrictEqual(_.intersperse(0)([1, 2, 3, 4]), [1, 0, 2, 0, 3, 0, 4]) }) + it('intercalate', () => { + U.deepStrictEqual(_.intercalate(S.Monoid)('-')([]), '') + U.deepStrictEqual(_.intercalate(S.Monoid)('-')(['a']), 'a') + U.deepStrictEqual(_.intercalate(S.Monoid)('-')(['a', 'b', 'c']), 'a-b-c') + U.deepStrictEqual(_.intercalate(S.Monoid)('-')(['a', '', 'c']), 'a--c') + U.deepStrictEqual(_.intercalate(S.Monoid)('-')(['a', 'b']), 'a-b') + U.deepStrictEqual(_.intercalate(S.Monoid)('-')(['a', 'b', 'c', 'd']), 'a-b-c-d') + }) + it('zipWith', () => { U.deepStrictEqual( _.zipWith([1, 2, 3], ['a', 'b', 'c', 'd'], (n, s) => s + n), diff --git a/test/NonEmptyArray.ts b/test/NonEmptyArray.ts index fc165c9ca..040f037de 100644 --- a/test/NonEmptyArray.ts +++ b/test/NonEmptyArray.ts @@ -187,6 +187,14 @@ describe('NonEmptyArray', () => { U.deepStrictEqual(_.intersperse(0)([1, 2, 3, 4]), [1, 0, 2, 0, 3, 0, 4]) }) + it('intercalate', () => { + U.deepStrictEqual(_.intercalate(S.Semigroup)('-')(['a']), 'a') + U.deepStrictEqual(_.intercalate(S.Semigroup)('-')(['a', 'b', 'c']), 'a-b-c') + U.deepStrictEqual(_.intercalate(S.Semigroup)('-')(['a', '', 'c']), 'a--c') + U.deepStrictEqual(_.intercalate(S.Semigroup)('-')(['a', 'b']), 'a-b') + U.deepStrictEqual(_.intercalate(S.Semigroup)('-')(['a', 'b', 'c', 'd']), 'a-b-c-d') + }) + it('reverse', () => { U.deepStrictEqual(_.reverse([1, 2, 3]), [3, 2, 1]) }) diff --git a/test/ReadonlyArray.ts b/test/ReadonlyArray.ts index 68205872c..58a4b83e1 100644 --- a/test/ReadonlyArray.ts +++ b/test/ReadonlyArray.ts @@ -802,6 +802,15 @@ describe('ReadonlyArray', () => { U.deepStrictEqual(_.intersperse(0)([1, 2, 3, 4]), [1, 0, 2, 0, 3, 0, 4]) }) + it('intercalate', () => { + U.deepStrictEqual(_.intercalate(S.Monoid)('-')([]), '') + U.deepStrictEqual(_.intercalate(S.Monoid)('-')(['a']), 'a') + U.deepStrictEqual(_.intercalate(S.Monoid)('-')(['a', 'b', 'c']), 'a-b-c') + U.deepStrictEqual(_.intercalate(S.Monoid)('-')(['a', '', 'c']), 'a--c') + U.deepStrictEqual(_.intercalate(S.Monoid)('-')(['a', 'b']), 'a-b') + U.deepStrictEqual(_.intercalate(S.Monoid)('-')(['a', 'b', 'c', 'd']), 'a-b-c-d') + }) + it('rotate', () => { U.strictEqual(_.rotate(0)(_.empty), _.empty) U.strictEqual(_.rotate(1)(_.empty), _.empty) diff --git a/test/ReadonlyNonEmptyArray.ts b/test/ReadonlyNonEmptyArray.ts index b9c957758..c5505fc5f 100644 --- a/test/ReadonlyNonEmptyArray.ts +++ b/test/ReadonlyNonEmptyArray.ts @@ -198,6 +198,14 @@ describe('ReadonlyNonEmptyArray', () => { U.deepStrictEqual(_.intersperse(0)([1, 2, 3, 4]), [1, 0, 2, 0, 3, 0, 4]) }) + it('intercalate', () => { + U.deepStrictEqual(_.intercalate(S.Semigroup)('-')(['a']), 'a') + U.deepStrictEqual(_.intercalate(S.Semigroup)('-')(['a', 'b', 'c']), 'a-b-c') + U.deepStrictEqual(_.intercalate(S.Semigroup)('-')(['a', '', 'c']), 'a--c') + U.deepStrictEqual(_.intercalate(S.Semigroup)('-')(['a', 'b']), 'a-b') + U.deepStrictEqual(_.intercalate(S.Semigroup)('-')(['a', 'b', 'c', 'd']), 'a-b-c-d') + }) + it('reverse', () => { const singleton: _.ReadonlyNonEmptyArray = [1] U.strictEqual(_.reverse(singleton), singleton)