Skip to content

Commit

Permalink
add more tests to Semigroupal
Browse files Browse the repository at this point in the history
  • Loading branch information
gcanti authored and mikearnaldi committed Oct 17, 2022
1 parent fff6dc0 commit 126d403
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 22 deletions.
86 changes: 65 additions & 21 deletions test/Semigroupal.ts
Original file line number Diff line number Diff line change
@@ -1,34 +1,78 @@
import { pipe } from "@fp-ts/core/internal/Function"
import * as _ from "@fp-ts/core/Semigroupal"
import * as O from "./data/Option"
import * as RA from "./data/ReadonlyArray"
import * as string from "./data/string"
import * as U from "./util"

describe("Semigroupal", () => {
it("zipWithComposition", () => {
describe("zipWithComposition", () => {
const sum = (a: number, b: number): number => a + b
const zipWith = _.zipWithComposition(O.Semigroupal, O.Semigroupal)
U.deepStrictEqual(pipe(O.none, zipWith(O.none, sum)), O.none)
U.deepStrictEqual(pipe(O.some(O.none), zipWith(O.none, sum)), O.none)
U.deepStrictEqual(pipe(O.some(O.some(1)), zipWith(O.none, sum)), O.none)
U.deepStrictEqual(pipe(O.some(O.some(1)), zipWith(O.some(O.none), sum)), O.some(O.none))
U.deepStrictEqual(pipe(O.some(O.none), zipWith(O.some(O.some(2)), sum)), O.some(O.none))
U.deepStrictEqual(pipe(O.some(O.some(1)), zipWith(O.some(O.some(2)), sum)), O.some(O.some(3)))
it("ReadonlyArray", () => {
const zipWith = _.zipWithComposition(RA.Semigroupal, O.Semigroupal)
U.deepStrictEqual(pipe([], zipWith([O.none], sum)), [])
U.deepStrictEqual(pipe([O.none], zipWith([], sum)), [])
U.deepStrictEqual(pipe([O.none], zipWith([O.none], sum)), [O.none])
U.deepStrictEqual(pipe([O.some(1)], zipWith([O.some(2)], sum)), [O.some(3)])
U.deepStrictEqual(pipe([O.some(1), O.none], zipWith([O.some(2)], sum)), [O.some(3), O.none])
U.deepStrictEqual(pipe([O.some(1), O.none], zipWith([O.some(2), O.some(3)], sum)), [
O.some(3),
O.some(4),
O.none,
O.none
])

it("Option", () => {
const sum = (a: number, b: number): number => a + b
const zipWith = _.zipWithComposition(O.Semigroupal, O.Semigroupal)
U.deepStrictEqual(pipe(O.none, zipWith(O.none, sum)), O.none)
U.deepStrictEqual(pipe(O.some(O.none), zipWith(O.none, sum)), O.none)
U.deepStrictEqual(pipe(O.some(O.some(1)), zipWith(O.none, sum)), O.none)
U.deepStrictEqual(pipe(O.some(O.some(1)), zipWith(O.some(O.none), sum)), O.some(O.none))
U.deepStrictEqual(pipe(O.some(O.none), zipWith(O.some(O.some(2)), sum)), O.some(O.none))
U.deepStrictEqual(
pipe(O.some(O.some(1)), zipWith(O.some(O.some(2)), sum)),
O.some(O.some(3))
)
})
})
})

it("zipManyComposition", () => {
const zipMany = _.zipManyComposition(O.Semigroupal, O.Semigroupal)
U.deepStrictEqual(pipe(O.none, zipMany([])), O.none)
U.deepStrictEqual(pipe(O.some(O.none), zipMany([])), O.some(O.none))
U.deepStrictEqual(pipe(O.some(O.some(1)), zipMany([])), O.some(O.some([1] as const)))
U.deepStrictEqual(pipe(O.none, zipMany([O.none])), O.none)
U.deepStrictEqual(pipe(O.some(O.none), zipMany([O.none])), O.none)
U.deepStrictEqual(pipe(O.some(O.none), zipMany([O.some(O.none)])), O.some(O.none))
U.deepStrictEqual(pipe(O.some(O.none), zipMany([O.some(O.some("a"))])), O.some(O.none))
U.deepStrictEqual(
pipe(O.some(O.some(1)), zipMany([O.some(O.some(2))])),
O.some(O.some([1, 2] as const))
)
describe("zipManyComposition", () => {
it("ReadonlyArray", () => {
const zipMany = _.zipManyComposition(RA.Semigroupal, O.Semigroupal)
U.deepStrictEqual(pipe([O.some(1), O.none], zipMany([])), [O.some([1] as const), O.none])
U.deepStrictEqual(pipe([O.some(1), O.none], zipMany([[O.some(2), O.none]])), [
O.some([1, 2] as const),
O.none,
O.none,
O.none
])
U.deepStrictEqual(
pipe([O.some(1), O.some(2)], zipMany([[O.some(3), O.some(4)], [O.some(5)]])),
[
O.some([1, 3, 5] as const),
O.some([1, 4, 5] as const),
O.some([2, 3, 5] as const),
O.some([2, 4, 5] as const)
]
)
})

it("Option", () => {
const zipMany = _.zipManyComposition(O.Semigroupal, O.Semigroupal)
U.deepStrictEqual(pipe(O.none, zipMany([])), O.none)
U.deepStrictEqual(pipe(O.some(O.none), zipMany([])), O.some(O.none))
U.deepStrictEqual(pipe(O.some(O.some(1)), zipMany([])), O.some(O.some([1] as const)))
U.deepStrictEqual(pipe(O.none, zipMany([O.none])), O.none)
U.deepStrictEqual(pipe(O.some(O.none), zipMany([O.none])), O.none)
U.deepStrictEqual(pipe(O.some(O.none), zipMany([O.some(O.none)])), O.some(O.none))
U.deepStrictEqual(pipe(O.some(O.none), zipMany([O.some(O.some("a"))])), O.some(O.none))
U.deepStrictEqual(
pipe(O.some(O.some(1)), zipMany([O.some(O.some(2))])),
O.some(O.some([1, 2] as const))
)
})
})

it("ap", () => {
Expand Down
39 changes: 38 additions & 1 deletion test/data/ReadonlyArray.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ import type * as foldableWithIndex from "@fp-ts/core/FoldableWithIndex"
import type * as functor from "@fp-ts/core/Functor"
import type * as functorWithIndex from "@fp-ts/core/FunctorWithIndex"
import type { Kind, TypeLambda } from "@fp-ts/core/HKT"
import { pipe } from "@fp-ts/core/internal/Function"
import type * as monoidal from "@fp-ts/core/Monoidal"
import type * as semigroupal from "@fp-ts/core/Semigroupal"
import type { Sortable } from "@fp-ts/core/Sortable"
import type * as traverse_ from "@fp-ts/core/Traversable"
import type * as traverseWithIndex_ from "@fp-ts/core/TraversableWithIndex"
Expand All @@ -14,8 +16,11 @@ export interface ReadonlyArrayTypeLambda extends TypeLambda {
readonly type: ReadonlyArray<this["Out1"]>
}

const map = <A, B>(f: (a: A) => B) =>
(self: ReadonlyArray<A>): ReadonlyArray<B> => self.map(a => f(a))

export const Functor: functor.Functor<ReadonlyArrayTypeLambda> = {
map: (f) => (self) => self.map(a => f(a))
map
}

export const FunctorWithIndex: functorWithIndex.FunctorWithIndex<ReadonlyArrayTypeLambda, number> =
Expand Down Expand Up @@ -90,3 +95,35 @@ export const TraverseWithIndex: traverseWithIndex_.TraversableWithIndex<
> = {
traverseWithIndex
}

export const zipWith = <B, A, C>(that: ReadonlyArray<B>, f: (a: A, b: B) => C) =>
(self: ReadonlyArray<A>): ReadonlyArray<C> => {
const out: Array<C> = []
for (const a of self) {
for (const b of that) {
out.push(f(a, b))
}
}
return out
}

export const Semigroupal: semigroupal.Semigroupal<ReadonlyArrayTypeLambda> = {
map,
zipWith,
zipMany: <A>(collection: Iterable<ReadonlyArray<A>>) =>
(self: ReadonlyArray<A>): ReadonlyArray<readonly [A, ...Array<A>]> => {
const fa: ReadonlyArray<readonly [A, ...Array<A>]> = pipe(
self,
Functor.map(a => [a] as const)
)
const fas = Array.from(collection)
if (fas.length === 0) {
return fa
}
let out = fa
for (const c of fas) {
out = pipe(out, zipWith(c, (a, b) => [...a, b]))
}
return out
}
}

0 comments on commit 126d403

Please sign in to comment.