diff --git a/src/types.ts b/src/types.ts index fe78895..ac2e9b9 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,6 +1,5 @@ export type { Result, Failure, Success } from '~/utils/adt/result' export type { Just, Maybe, Nothing } from '~/utils/adt/maybe' -export type { Curry } from '~/utils/composition/curry' export type { Compose } from '~/utils/composition/compose' export type { Reduce } from '~/utils/typeclass/foldable' export type { Pipe } from '~/utils/composition/pipe' diff --git a/src/utils/composition/compose.ts b/src/utils/composition/compose.ts index d5edee3..575bf2c 100644 --- a/src/utils/composition/compose.ts +++ b/src/utils/composition/compose.ts @@ -4,14 +4,14 @@ * @module compose */ -import { curry } from '~/utils/composition/curry' -import { reduce } from '~/utils/typeclass/foldable' +/** To pattern match values. */ +import { match } from '~/utils/control-flow/match' -/** @typeParam T */ -type Fn = (a: T) => T +/** Function that takes a value of type A and returns a value of type A. */ +type Fn = (a: A) => A -/** @template T */ -export type Fx = ReadonlyArray> +/** An array of functions {@link Fn}. */ +export type Fx = ReadonlyArray> /** * @template T @@ -33,7 +33,10 @@ export type Compose = (a: Fx) => (b: T) => T * types do not match/. That needs to be fixed. */ export const compose: Compose = (fx: Fx): ((x: T) => T) => { - const fn = (g: T, f: Fn) => f(g) - const reducer = curry(reduce)(fn) - return (x: T) => reducer(x)(fx) + return match(fx.length) + .with(0, () => (x: T) => x) + .otherwise(() => { + const [head, ...tail] = fx + return (x: T) => compose(tail)(head(x)) + }) } diff --git a/src/utils/composition/curry.ts b/src/utils/composition/curry.ts deleted file mode 100644 index 8d0ba93..0000000 --- a/src/utils/composition/curry.ts +++ /dev/null @@ -1,54 +0,0 @@ -/** - * Currying utils. - * - * @module curry - */ - -import { nothing } from '~/utils/adt/maybe' -import { match } from '~/utils/control-flow/match' - -/** - * @typeParam P - * @typeParam R - */ -type Fn

= (...args: P) => R - -/** @typeParam T */ -type Head = T extends [any, ...any[]] ? T[0] : never - -/** @typeParam T */ -type Tail = T extends [any, ...infer U] ? U : never - -/** - * @typeParam P - * @typeParam R - */ -export type Curry

= - Fn extends Fn - ? T extends [] - ? U - : (arg: Head) => Curry, U> - : never - -/** - * @overload - * @typeParam P - * @typeParam R - * @param {Fn} fn - The function to be curried. - * @returns {Curry} - The curried function. - */ - -/** - * Curry a function - * - * @param {function} fn - The function to be curried - * @returns {function} - The curried function - * @see {@link https://blog.openreplay.com/forever-functional-complex-typing-in-typescript-part-2/} - */ -export const curry = (fn: Fn) => { - return match(fn.length) - .with(0, () => fn()) - .otherwise(() => { - return (x: any) => curry(fn.bind(nothing, x)) - }) -} diff --git a/test/unit/utils/composition/curry.test.ts b/test/unit/utils/composition/curry.test.ts deleted file mode 100644 index 5aee6f3..0000000 --- a/test/unit/utils/composition/curry.test.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { describe, expect, test } from 'vitest' - -import { curry } from '~/utils/composition/curry' -import { reduce } from '~/utils/typeclass/foldable' - -type Add = (a: A, b: A) => A - -describe('curry2/1', () => { - describe('Given a function/2', () => { - const f: Add = (a, b) => a + b - - test('When currying and executing it', () => { - const result = curry(f)(1)(2) - expect(result).toBe(3) - }) - }) -}) - -describe('curry3/1', () => { - describe('Given a function/3', () => { - const f = reduce - const fn: Add = (a, b) => a + b - const init = 1 - const values = [2, 3, 4] - - test('When currying and executing it', () => { - const result = curry(f)(fn)(init)(values) - expect(result).toBe(10) - }) - }) -})