From d9723d74c8c391412585bdb3853d32e38a59b7ee Mon Sep 17 00:00:00 2001 From: poteat Date: Fri, 23 Aug 2024 12:33:10 -0700 Subject: [PATCH 01/17] docs: provide module-level documentation --- src/$.ts | 13 +++++++++++++ src/boolean.ts | 13 +++++++++++++ src/combinator.ts | 7 +++++++ src/conditional.ts | 16 ++++++++++++++++ src/digit-list.ts | 14 ++++++++++++++ src/digit.ts | 13 +++++++++++++ src/function.ts | 14 ++++++++++++++ src/index.ts | 2 -- src/integer.ts | 13 +++++++++++++ src/kind.ts | 14 ++++++++++++++ src/list.ts | 14 ++++++++++++++ src/natural-number-theory.ts | 14 ++++++++++++++ src/natural-number.ts | 14 ++++++++++++++ src/number.ts | 13 +++++++++++++ src/object.ts | 13 +++++++++++++ src/parser.ts | 26 ++++++++++++++++++++++++++ src/stress.ts | 15 +++++++++++++++ src/string.ts | 13 +++++++++++++ src/test.ts | 14 ++++++++++++++ src/type.ts | 13 +++++++++++++ src/union.ts | 13 +++++++++++++ 21 files changed, 279 insertions(+), 2 deletions(-) diff --git a/src/$.ts b/src/$.ts index eb7028a21..72dae7924 100644 --- a/src/$.ts +++ b/src/$.ts @@ -1 +1,14 @@ export * from './$/' + +/** + * The `$` module contains various type-level utilities for applying type-level + * functions to arguments. + * + * @example + * ```ts + * import { $, List, String } from 'hkt-toolbelt' + * + * type Result = $, ['foo', 'bar']> // ['FOO', 'BAR'] + * ``` + */ +declare module './$' {} diff --git a/src/boolean.ts b/src/boolean.ts index 31e0a2abe..c2898665f 100644 --- a/src/boolean.ts +++ b/src/boolean.ts @@ -1 +1,14 @@ export * from './boolean/' + +/** + * The `Boolean` module contains various boolean type utilities. These utilities + * are used to perform logical operations on boolean types. + * + * @example + * ```ts + * import { $, Boolean } from 'hkt-toolbelt' + * + * type Result = $, false> // false + * ``` + */ +declare module './boolean' {} diff --git a/src/combinator.ts b/src/combinator.ts index a77436d8f..2e3ba4758 100644 --- a/src/combinator.ts +++ b/src/combinator.ts @@ -1 +1,8 @@ export * from './combinator/' + +/** + * The `Combinator` module contains various combinators. These are higher-order + * abstract functions that are applied to modify the behavior of other + * type-level functions. + */ +declare module './combinator' {} diff --git a/src/conditional.ts b/src/conditional.ts index 06f6c992d..e27c5a21d 100644 --- a/src/conditional.ts +++ b/src/conditional.ts @@ -1 +1,17 @@ export * from './conditional/' + +/** + * The `Conditional` module contains various conditional type utilities. These + * utilities are used to express conditional logic in type-level programming. + * + * @example + * ```ts + * import { $, Conditional } from 'hkt-toolbelt' + * + * type MyFcn = $<$, 'foo'>, 'bar'> + * + * type Result = $ // 'foo' + * type Result2 = $ // 'bar' + * ``` + */ +declare module './conditional' {} diff --git a/src/digit-list.ts b/src/digit-list.ts index 11fe04557..6eb41ba2e 100644 --- a/src/digit-list.ts +++ b/src/digit-list.ts @@ -1 +1,15 @@ export * from './digit-list/' + +/** + * The `DigitList` module contains various utilities for working with digit + * lists. Digit lists are a type-level representation of lists of decimal digits + * (0-9). They are used in various contexts, such as representing numbers. + * + * @example + * ```ts + * import { $, DigitList } from 'hkt-toolbelt' + * + * type Result = $<$, [4, 5, 6]> // [5, 7, 9] + * ``` + */ +declare module './digit-list' {} diff --git a/src/digit.ts b/src/digit.ts index 823ad4bd5..6054fab32 100644 --- a/src/digit.ts +++ b/src/digit.ts @@ -1 +1,14 @@ export * from './digit/' + +/** + * The `Digit` module contains various utilities for working with decimal digits + * (0-9). Digits are used in various contexts, such as representing numbers. + * + * @example + * ```ts + * import { $, Digit } from 'hkt-toolbelt' + * + * type Result = $<$, 2> // 3 + * ``` + */ +declare module './digit' {} diff --git a/src/function.ts b/src/function.ts index 56294782d..292133b54 100644 --- a/src/function.ts +++ b/src/function.ts @@ -1 +1,15 @@ export * from './function/' + +/** + * The `Function` module contains various utilities for working with function + * types. Function types are used in various contexts, such as representing + * higher-order functions. + * + * @example + * ```ts + * import { $, Function } from 'hkt-toolbelt' + * + * type Result = $<$ string>, 42> // string + * ``` + */ +declare module './function' {} diff --git a/src/index.ts b/src/index.ts index 03389c9b9..3a9c246b0 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,3 @@ -/* eslint-disable unused-imports/no-unused-imports */ - import * as $ from './$' export { $, $$, $N } from './$' diff --git a/src/integer.ts b/src/integer.ts index 477be2fe6..25fb8513a 100644 --- a/src/integer.ts +++ b/src/integer.ts @@ -1 +1,14 @@ export * from './integer/' + +/** + * The `Integer` module contains various utilities for working with integer + * types, i.e. signed and unsigned integers. + * + * @example + * ```ts + * import { $, Integer } from 'hkt-toolbelt' + * + * type Result = $<$, -2> // -1 + * ``` + */ +declare module './integer' {} diff --git a/src/kind.ts b/src/kind.ts index ba50cc9e7..ea68d1207 100644 --- a/src/kind.ts +++ b/src/kind.ts @@ -1 +1,15 @@ export * from './kind/' + +/** + * The `Kind` module contains various utilities for working with higher-kinded + * types. Higher-kinded types are used in various contexts, such as representing + * and manipulating higher-order functions, and composing types. + * + * @example + * ```ts + * import { $, Kind } from 'hkt-toolbelt' + * + * type Result = $<$, Function.Identity> // [1, 2, 3] + * ``` + */ +declare module './kind' {} diff --git a/src/list.ts b/src/list.ts index d69b0e5c9..0b34dcb49 100644 --- a/src/list.ts +++ b/src/list.ts @@ -1 +1,15 @@ export * from './list/' + +/** + * The `List` module contains various utilities for working with type-level + * tuples. It provides utilities such as mapping, filtering, and reducing + * operations. + * + * @example + * ```ts + * import { $, List, String } from 'hkt-toolbelt' + * + * type Result = $ // ['FOO', 'BAR'] + * ``` + */ +declare module './list' {} diff --git a/src/natural-number-theory.ts b/src/natural-number-theory.ts index b2921847b..fd2951a59 100644 --- a/src/natural-number-theory.ts +++ b/src/natural-number-theory.ts @@ -1 +1,15 @@ export * from './natural-number-theory/' + +/** + * The `NaturalNumberTheory` module contains various novelty utilities for + * computing natural number sequences and operations. It provides utilities such + * as collatz, factorial, etc. + * + * @example + * ```ts + * import { $, NaturalNumberTheory } from 'hkt-toolbelt' + * + * type Result = $ // 120 + * ``` + */ +declare module './natural-number-theory' {} diff --git a/src/natural-number.ts b/src/natural-number.ts index 489e976b7..270ceae4f 100644 --- a/src/natural-number.ts +++ b/src/natural-number.ts @@ -1 +1,15 @@ export * from './natural-number/' + +/** + * The `NaturalNumber` module contains various utilities for working with + * natural numbers, i.e. integers above or equal to zero. It provides utilities + * such as addition, comparison, etc. + * + * @example + * ```ts + * import { $, NaturalNumber } from 'hkt-toolbelt' + * + * type Result = $ // 6 + * ``` + */ +declare module './natural-number' {} diff --git a/src/number.ts b/src/number.ts index 49446696b..e36e74a9a 100644 --- a/src/number.ts +++ b/src/number.ts @@ -1 +1,14 @@ export * from './number/' + +/** + * The `Number` module contains various utilities for working with + * including absolute values, comparisons, etc. + * + * @example + * ```ts + * import { $, Number } from 'hkt-toolbelt' + * + * type Result = $ // 42 + * ``` + */ +declare module './number' {} diff --git a/src/object.ts b/src/object.ts index 23db66b90..8313657ad 100644 --- a/src/object.ts +++ b/src/object.ts @@ -1 +1,14 @@ export * from './object/' + +/** + * The `Object` module contains various utilities for working with + * objects, including getting and setting values, merging, etc. + * + * @example + * ```ts + * import { $, Object } from 'hkt-toolbelt' + * + * type Result = $ // 'foo' + * ``` + */ +declare module './object' {} diff --git a/src/parser.ts b/src/parser.ts index 8b0a61d50..028ac9138 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -1 +1,27 @@ export * from './parser/' + +/** + * The `Parser` module contains various utilities for building type-level + * parsers, which take in a string literal and return a type representing the + * result of parsing the string. + * + * These utilities are particularly useful for parsing input strings and + * converting them into more meaningful types. + * + * @example + * ```ts + * import { $, Parser } from "hkt-toolbelt"; + * + * type Result = $< + * $< + * Parser.Run, + * $< + * Parser.Sequence, + * [$, $, Parser.Letters] + * > + * >, + * 'hello worlds' + * > // ["hello", " ", "worlds"] + * ``` + */ +declare module './parser' {} diff --git a/src/stress.ts b/src/stress.ts index da572eca5..fd7e07f57 100644 --- a/src/stress.ts +++ b/src/stress.ts @@ -1 +1,16 @@ export * from './stress/' + +/** + * The `Stress` module contains various utilities for stress testing + * type-level functions, including generating large tuples and objects. This is + * used internally to ensure that type-level functions are robust and can handle + * large inputs without crashing. + * + * @example + * ```ts + * import { $, Stress, List } from 'hkt-toolbelt' + * + * type Result = $ // 100 + * ``` + */ +declare module './stress' {} diff --git a/src/string.ts b/src/string.ts index 0103a767c..4bc1e0644 100644 --- a/src/string.ts +++ b/src/string.ts @@ -1 +1,14 @@ export * from './string/' + +/** + * The `String` module contains various utilities for working with + * strings, including manipulating string types, joining strings, etc. + * + * @example + * ```ts + * import { $, String } from 'hkt-toolbelt' + * + * type Result = $<$, 'foo'> // 'foobar' + * ``` + */ +declare module './string' {} diff --git a/src/test.ts b/src/test.ts index 4419b2be8..14526df7d 100644 --- a/src/test.ts +++ b/src/test.ts @@ -1 +1,15 @@ export * from './test/' + +/** + * The `Test` module contains various utilities for testing type-level + * functions, including expecting types to be equal, etc. This is used + * internally to ensure correctness. + * + * @example + * ```ts + * import { $, Test } from 'hkt-toolbelt' + * + * type Result = Test.Expect // compiler error + * ``` + */ +declare module './test' {} diff --git a/src/type.ts b/src/type.ts index b9c272e7f..fcd1ece03 100644 --- a/src/type.ts +++ b/src/type.ts @@ -1 +1,14 @@ export * from './type/' + +/** + * The `Type` module contains various utilities for working with + * types, including casting, displaying, and inferring types. + * + * @example + * ```ts + * import { $, Type } from 'hkt-toolbelt' + * + * type Result = Type._$cast<42, number> // 42 + * ``` + */ +declare module './type' {} diff --git a/src/union.ts b/src/union.ts index 55b4c66c3..1553a068f 100644 --- a/src/union.ts +++ b/src/union.ts @@ -1 +1,14 @@ export * from './union/' + +/** + * The `Union` module contains various utilities for working with union types, + * including converting to intersections, lists, etc. + * + * @example + * ```ts + * import { $, Union } from 'hkt-toolbelt' + * + * type Result = $ // 3 + * ``` + */ +declare module './union' {} From 2be288d5c7c2952b9f62cfd6faeb79110214998e Mon Sep 17 00:00:00 2001 From: poteat Date: Mon, 23 Sep 2024 18:03:33 -0700 Subject: [PATCH 02/17] chore: setup jest test support --- .gitignore | 2 ++ jest.config.js | 8 ++++++++ package.json | 12 +++++++++--- 3 files changed, 19 insertions(+), 3 deletions(-) create mode 100644 jest.config.js diff --git a/.gitignore b/.gitignore index c90625fbb..a0ec120e1 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,5 @@ wiki .aider* .multi-aider-ignore .DS_Store + +!jest.config.js \ No newline at end of file diff --git a/jest.config.js b/jest.config.js new file mode 100644 index 000000000..eae75ab8f --- /dev/null +++ b/jest.config.js @@ -0,0 +1,8 @@ +/** @type {import('ts-jest').JestConfigWithTsJest} **/ +module.exports = { + testEnvironment: 'node', + transform: { + '^.+.tsx?$': ['ts-jest', {}] + }, + passWithNoTests: true +} diff --git a/package.json b/package.json index f44615bcb..3ec52adf5 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "hkt-toolbelt", "private": true, "scripts": { - "test": "NODE_OPTIONS=--max-old-space-size=8192 tsc --project tsconfig.spec.json", + "test": "NODE_OPTIONS=--max-old-space-size=8192 tsc --project tsconfig.spec.json && jest", "stress": "NODE_OPTIONS=--max-old-space-size=24576 tsc --project tsconfig.stress.json", "build": "./build.sh", "build:docs": "typedoc --skipErrorChecking", @@ -17,6 +17,9 @@ }, "license": "MIT", "devDependencies": { + "@types/jest": "^29.5.12", + "@types/lodash": "^4.17.7", + "@types/mustache": "^4.2.5", "@typescript-eslint/eslint-plugin": "^7.2.0", "@typescript-eslint/parser": "^7.2.0", "eslint": "^8.57.0", @@ -27,11 +30,14 @@ "eslint-plugin-jsdoc": "^48.2.1", "eslint-plugin-prettier": "^5.1.3", "eslint-plugin-unused-imports": "^3.1.0", + "jest": "^29.7.0", + "lodash": "^4.17.21", + "mustache": "^4.2.0", "prettier": "^3.2.5", "prettier-plugin-organize-imports": "^3.2.4", - "typedoc": "^0.25.3" + "ts-jest": "^29.2.5" }, "dependencies": { - "typescript": "~5.4.2" + "typescript": "^5.5.4" } } From 7dfc45dd91c7373cd7064254f9fc34d9ccefe679 Mon Sep 17 00:00:00 2001 From: poteat Date: Mon, 23 Sep 2024 18:03:57 -0700 Subject: [PATCH 03/17] feat: add mustache readme template --- docs/readme.md | 6960 +++++++++++++++++++++++++++++++++++++++ docs/readme.template.md | 51 + 2 files changed, 7011 insertions(+) create mode 100644 docs/readme.md create mode 100644 docs/readme.template.md diff --git a/docs/readme.md b/docs/readme.md new file mode 100644 index 000000000..9a094abc0 --- /dev/null +++ b/docs/readme.md @@ -0,0 +1,6960 @@ +# HKT Toolbelt + +The HKT Toolbelt is a collection of type-level utilities that can be mapped and combined in functional ways using higher-kinded types. + +For example, you can map and pipe type-level functions: + +```ts +import { $, List, String } from 'hkt-toolbelt' + +type Result = $< + List.Map, + ['foo', 'bar'] // ['FOO', 'BAR'] +> +``` + +We provide utilities around string manipulation, object mapping, arithmetic, looping, parsing, and more. + +The toolbelt has 280 utilities organized into 22 modules. + +# Module List + +| Module name | Description | +| -- | -- | +| [\$](#module) | The `$` module contains various type-level utilities for applying type-level functions to arguments. | +| [Boolean](#module-boolean) | The `Boolean` module contains various boolean type utilities. These utilities are used to perform logical operations on boolean types. | +| [Combinator](#module-combinator) | The `Combinator` module contains various combinators. These are higher-order abstract functions that are applied to modify the behavior of other type-level functions. | +| [Conditional](#module-conditional) | The `Conditional` module contains various conditional type utilities. These utilities are used to express conditional logic in type-level programming. | +| [Digit](#module-digit) | The `Digit` module contains various utilities for working with decimal digits (0-9). Digits are used in various contexts, such as representing numbers. | +| [DigitList](#module-digitlist) | The `DigitList` module contains various utilities for working with digit lists. Digit lists are a type-level representation of lists of decimal digits (0-9). They are used in various contexts, such as representing numbers. | +| [Function](#module-function) | The `Function` module contains various utilities for working with function types. Function types are used in various contexts, such as representing higher-order functions. | +| [Integer](#module-integer) | The `Integer` module contains various utilities for working with integer types, i.e. signed and unsigned integers. | +| [Kind](#module-kind) | The `Kind` module contains various utilities for working with higher-kinded types. Higher-kinded types are used in various contexts, such as representing and manipulating higher-order functions, and composing types. | +| [List](#module-list) | The `List` module contains various utilities for working with type-level tuples. It provides utilities such as mapping, filtering, and reducing operations. | +| [Loop](#module-loop) | The `Loop` module contains various utilities for working with loops. Loops are a type-level programming construct that allows you to repeat a block of code until a certain condition is met. | +| [Matrix](#module-matrix) | The `Matrix` module contains various utilities for working with matrices. Matrices are represented as arrays of arrays, i.e. an array of rows. | +| [NaturalNumber](#module-naturalnumber) | The `NaturalNumber` module contains various utilities for working with natural numbers, i.e. integers above or equal to zero. It provides utilities such as addition, comparison, etc. | +| [NaturalNumberTheory](#module-naturalnumbertheory) | The `NaturalNumberTheory` module contains various novelty utilities for computing natural number sequences and operations. It provides utilities such as collatz, factorial, etc. | +| [Number](#module-number) | The `Number` module contains various utilities for working with including absolute values, comparisons, etc. | +| [Object](#module-object) | The `Object` module contains various utilities for working with objects, including getting and setting values, merging, etc. | +| [Parser](#module-parser) | The `Parser` module contains various utilities for building type-level parsers, which take in a string literal and return a type representing the result of parsing the string. | +| [Stress](#module-stress) | The `Stress` module contains various utilities for stress testing type-level functions, including generating large tuples and objects. This is used internally to ensure that type-level functions are robust and can handle large inputs without crashing. | +| [String](#module-string) | The `String` module contains various utilities for working with strings, including manipulating string types, joining strings, etc. | +| [Test](#module-test) | The `Test` module contains various utilities for testing type-level functions, including expecting types to be equal, etc. This is used internally to ensure correctness. | +| [Type](#module-type) | The `Type` module contains various utilities for working with types, including casting, displaying, and inferring types. | +| [Union](#module-union) | The `Union` module contains various utilities for working with union types, including converting to intersections, lists, etc. | + + +# Module: $ + +The `$` module contains various type-level utilities for applying type-level +functions to arguments. + + +```ts +import { $, String } from 'hkt-toolbelt' + +type Result = $ // 'FOO' +``` + + +| Utility name | Description | +| -- | -- | + | [\$](#utility-) | `$` is the most fundamental type in `hkt-toolbelt`. `$` is a generic type which takes in a type-level function and an input type, and returns the resultant output type of the type-level function, when applied to the input. | + | [\$\$](#utility-) | `$$` is a type-level function in `hkt-toolbelt` that allows users to pipe multiple type-level functions together and apply them to an input. | + | [\$N](#utility-n) | `$N` is a type-level function that applies a type-level function to a list of arguments. | + + +## Utility: \$.\$ + +`$` is the most fundamental type in `hkt-toolbelt`. `$` is a generic type +which takes in a type-level function and an input type, and returns the +resultant output type of the type-level function, when applied to the input. + +This is a type-level equivalent of an 'apply' function. + +`$` operates via partial application. This means that `$` can be used to +partially apply a type-level function, and then apply the partially applied +type-level function to a different input type. All applications of `$` must +be curried. + +### Type-Level Function Application + +The reason that we use `$` instead of normal generic type parameters is that +we want to be able to partially apply type-level functions. If we used +normal generic type parameters, we would not be able to perform partial +application, nor would we be able to take in or reference 'unapplied' types. + +As well, in base TypeScript, generics may not take in other generics. In +other words, the following is not valid TypeScript: + +```ts +type Apply = F; // 'Type 'F' is not generic.' +``` + +If we wanted to create a 'Map' type, we would not be able to do so with +normal generic type parameters. Instead, we would need to use a higher-order +type-level function. That is what `hkt-toolbelt` provides. + +| Argument name | Type | Description | +| -- | -- | -- | +| F | `Kind` | A type-level function. | +| X | `InputOf` | The input type to apply the type-level function to. | + +#### Basic Usage + + +For example, `Function.Identity` is a type-level function which takes in one +argument: the input type. `Function.Identity` returns the input type that was +passed in. + +Applying `Function.Identity` to a type will result in the type that was +passed in: + +```ts +import { Kind, Function } from "hkt-toolbelt"; +type Result = $; // "foo" +``` + + +For example, `String.Append` is a type-level function which takes in two +arguments: first, the string to append, and second, the string to append to. + +Only applying `String.Append` to one argument will result in a partially +applied type-level function. This partially applied type-level function can +then be applied to a different input type. + +```ts +import { Kind, String } from "hkt-toolbelt"; +type AppendBar = $; +type Result = $; // "foobar" +``` + +Intermediary type aliases are not necessary, but they can be useful for +readability. The following example is equivalent to the previous example. + +```ts +import { Kind, String } from "hkt-toolbelt"; +type Result = $<$, "foo">; // "foobar" +``` + +#### Advanced Usage + + +For example, `List.Map` is a type-level function which takes in two +arguments: first, a type-level function, and second, a list. `List.Map` +returns a list of the same length as the input list, where each element is +the result of applying the type-level function to the corresponding element +in the input list. + +This example applies `List.Map` to a partially applied `String.Append` type- +level function, and a list of strings. The result is a list of strings, where +each string has been appended with the string "bar". + +```ts +import { Kind, List, String } from "hkt-toolbelt"; +type Result = $< + $, + ["foo", "baz"] +>; // ["foobar", "bazbar"] +``` + +This example is a nice demonstration of functionality that cannot easily be +achieved with normal generic type parameters. + + +For example, `List.Filter` is a type-level function which takes in two +arguments: first, a type-level function, and second, a list. `List.Filter` +will only return the elements of the input list where the type-level +function returns the type `true`. + +This example applies `List.Filter` to a partially applied `String.Includes`, +and a list of strings. The result is a list of strings, where each string +includes the string "bar". + +Here we show where each intermediary step has been given a type alias. This +is not necessary, but it can be useful for readability and reusability. + +```ts +import { Kind, List, String } from "hkt-toolbelt"; + +// Does the string include "bar"? +type IncludesBar = $; + +// Filter the list for strings that include "bar". +type FilterForBar = $; + +// Apply the filter to the list. +type Result = $< + FilterForBar, + ["foo", "foobar", "baz", "barqux"] +>; // ["foobar", "barqux"] +``` + +In conclusion, `hkt-toolbelt` provides a powerful set of type-level +functions, which can be used to create complex type-level logic. The `$` +type is the most fundamental type in `hkt-toolbelt`, and is used to apply +type-level functions to input types. + + + +## Utility: \$.\$\$ + +`$$` is a type-level function in `hkt-toolbelt` that allows users to pipe +multiple type-level functions together and apply them to an input. + +### Purpose + +`hkt-toolbelt` provides a variety of higher-order type-level functions that +enable users to create complex type-level logic. However, it can be +challenging to apply multiple type-level functions to an input without +resorting to using intermediary type aliases. + +For example, imagine we want to append a string to a list of strings and +then join the resulting list. We would write this as the following, using +`Kind.Pipe`. + +`Kind.Pipe` is a type-level function that takes a tuple of type-level +functions and composes them from left to right. + +```ts +import { Kind, List, String } from "hkt-toolbelt"; + +type Result = $< + $, + $ + ]>, + ["bar", "baz"] +> // "bar baz foo" +``` + +This is quite verbose. We can use `$$` to make this code more readable: + +```ts +import { Kind, List, String, $$ } from "hkt-toolbelt"; + +type Result = $$< + [ + $, + $ + ], + ["bar", "baz"] +>; // "bar baz foo" +``` + +Here, `$$` is being used to pipe `List.Push` and `String.Join` together and +then apply them to a list of strings. + +| Argument name | Type | Description | +| -- | -- | -- | +| FX | `Kind[]` | A tuple of type-level functions that will be piped together. | +| X | `InputOf` | The input type that the type-level functions will be applied to. | + +#### Basic Usage + + +Here's a basic example that uses `$$` to apply a type-level function to an +input type: + +```ts +import { Kind, List, $$ } from "hkt-toolbelt"; + +type Result = $$< + [$, List.Unshift<"foo">], + [1, 2, 3] +>; // ["foo", 1, 2, 3, "bar"] +``` + +Here, `List.Push` and `List.Unshift` are being piped together using `$$` to +append "bar" to a list of numbers and then prepend "foo". + +#### Errors + +`$$` will enforce that the Nth type-level function's output is a subtype of +the (N + 1)th input. If this is not the case, `$$` will return the `never` +type. + +If you receive a `never` type, it can be helpful to use the `Kind.InputOf` +and `Kind.OutputOf` type-level functions to inspect the input and output +types of the type-level functions that you are piping together. + + + +## Utility: \$.\$N + +`$N` is a type-level function that applies a type-level function to a list of +arguments. + +This is syntactic sugar for nested `$` applications. In some sense this is +the contrapositive of `$$`, in that `$$` pipes a value through a list of +functions, while `$N` pipes a list of values through a function. + +There is no specific type checking to ensure the elements of the list are +subtypes of the input type of the type-level function. + +| Argument name | Type | Description | +| -- | -- | -- | +| K | `Kind` | The type-level function to apply. | +| X | `List` | The list of arguments to apply the type-level function to. | + +Since all type-level functions are curried, we successively apply the +type-level function to each argument in the list. + +This is useful for applying a type-level function that takes many arguments, +such as conditionals. + + +For example, `Function.If` is a type-level function which takes in four +arguments: a predicate, a truthy branch, a falsy branch, and an input type. + +Let's consider a function that emits 'even' if the input number is even, and +'odd' if the input number is odd: + +```ts +import { $, $N, Conditional, Function, NaturalNumber } from "hkt-toolbelt"; + +type Parity = $N< + Conditional.If, + [ + NaturalNumber.IsEven, + $, + $ + ] +>; + +type Result = $; // "even" +``` + +Here, we apply `Conditional.If` to a list of arguments. The first argument is +`NaturalNumber.IsEven`, which is a type-level function that takes in a +`NaturalNumber` and returns `true` if the number is even, and `false` +otherwise. The second argument is a type-level function that always returns +the string "even". The third argument is a type-level function that always +returns the string "odd". + +Since all type-level functions are curried, the resultant `Parity` type-level +function may be applied to get the result. + + + +# Module: Boolean + +The `Boolean` module contains various boolean type utilities. These utilities +are used to perform logical operations on boolean types. + + +```ts +import { $, Boolean } from 'hkt-toolbelt' + +type Result = $, false> // false +``` + + +| Utility name | Description | +| -- | -- | + | [AndAll](#utility-booleanandall) | `AndAll` is a type-level function that checks whether all elements in a sequence of booleans are `true`. | + | [And](#utility-booleanand) | `And` is a type-level function that takes in two boolean types, `T` and `U`, and returns the boolean result of applying the 'and' logical operation on `T` and `U`. | + | [Imply](#utility-booleanimply) | `Imply` is a type-level function that takes in two boolean types, `T` and `U`, and returns the boolean result of applying the 'imply' logical operation on `T` and `U`. | + | [NandAll](#utility-booleannandall) | `NandAll` is a type-level function that checks whether none of the elements in a sequence of boolean values are `true`. | + | [Nand](#utility-booleannand) | `Nand` is a type-level function that takes in two boolean types, `T` and `U`, and returns the boolean result of applying the 'nand' logical operation on `T` and `U`. | + | [Nimply](#utility-booleannimply) | `Nimply` is a type-level function that takes in two boolean types, `T` and `U`, and returns the boolean result of applying the 'not-implies' logical operation on `T` and `U`. | + | [NorAll](#utility-booleannorall) | `NorAll` is a type-level function that returns true only if every element in the given sequence of booleans is false. | + | [Nor](#utility-booleannor) | `Nor` is a type-level function that takes in two boolean types, `T` and `U`, and returns the boolean result of applying the 'nor' logical operation on `T` and `U`. | + | [Not](#utility-booleannot) | `Not` is a type-level function that takes in a boolean type `T`, and returns the boolean result of applying the 'not' logical operation on `T`. | + | [OrAll](#utility-booleanorall) | `OrAll` is a type-level function that returns true if any of the elements in the given sequence of booleans are true. | + | [Or](#utility-booleanor) | `Or` is a type-level function that takes in two boolean types, `T` and `U`, and returns the boolean result of applying the 'or' logical operation on `T` and `U`. | + | [XnorAll](#utility-booleanxnorall) | `XnorAll` is a type-level function that returns true if an odd number of elements in the given sequence of booleans are true. | + | [Xnor](#utility-booleanxnor) | `Xnor` is a type-level function that takes in two boolean types, `T` and `U`, and returns the boolean result of applying the 'xnor' logical operation on `T` and `U`. | + | [Xor](#utility-booleanxor) | `Xor` is a type-level function that takes in two boolean types, `T` and `U`, and returns the boolean result of applying the 'exclusive or' (xor) logical operation on `T` and `U`. | + + +## Utility: Boolean.AndAll + +`AndAll` is a type-level function that checks whether all elements in a +sequence of booleans are `true`. + +| Argument name | Type | Description | +| -- | -- | -- | +| T | `boolean[]` | The boolean array to check. | + + +For example, we can use `AndAll` to check if all elements in a boolean array +are `true`. In this example, we have an array with all elements being `true`: + +We apply `AndAll` to the boolean array using the `$` type-level applicator: + +```ts +import { $, Boolean } from "hkt-toolbelt"; + +type Result = $; // true +``` + + + +## Utility: Boolean.And + +`And` is a type-level function that takes in two boolean types, `T` and +`U`, and returns the boolean result of applying the 'and' logical operation +on `T` and `U`. + +| Argument name | Type | Description | +| -- | -- | -- | +| T | `boolean` | A boolean type. | +| U | `boolean` | A boolean type. | + + +For example, we can use `And` to determine whether two boolean types are +both true. In this example, `true` and `false` are passed as type arguments +to the type-level function: + +We apply `And` to `true` and `false` respectively using the `$` type-level +applicator: + +```ts +import { $, Boolean } from "hkt-toolbelt"; + +type Result = $<$, false>; // false +``` + + + +## Utility: Boolean.Imply + +`Imply` is a type-level function that takes in two boolean types, `T` and +`U`, and returns the boolean result of applying the 'imply' logical +operation on `T` and `U`. + +This is also known as the 'logical implication' operator. + +| Argument name | Type | Description | +| -- | -- | -- | +| T | `boolean` | A boolean type. | +| U | `boolean` | A boolean type. | + + +For example, we can use `Imply` to determine whether a statement is true +given the truth values of two propositions, `T` and `U`. In this example, +`true` and `false` are passed as type arguments to the type-level function: + +We apply `Imply` to `true` and `false` respectively using the `$` type-level +applicator: + +```ts +import { $, Boolean } from "hkt-toolbelt"; + +type Result = $<$, false>; // false +``` + + + +## Utility: Boolean.NandAll + +`NandAll` is a type-level function that checks whether none of the elements +in a sequence of boolean values are `true`. + +| Argument name | Type | Description | +| -- | -- | -- | +| T | `boolean[]` | The boolean array to check. | + + +For example, we can use `NandAll` to check if none of the elements in a +boolean array are `true`. In this example, we have an array with all elements +being `false`: + +We apply `NandAll` to the boolean array using the `$` type-level applicator: + +```ts +import { $, Boolean } from "hkt-toolbelt"; + +type Result = $; // true +``` + + + +## Utility: Boolean.Nand + +`Nand` is a type-level function that takes in two boolean types, `T` and +`U`, and returns the boolean result of applying the 'nand' logical operation +on `T` and `U`. + +| Argument name | Type | Description | +| -- | -- | -- | +| T | `boolean` | A boolean type. | +| U | `boolean` | A boolean type. | + + +For example, we can use `Nand` to determine whether two boolean types are +not both true. In this example, `true` and `false` are passed as type +arguments to the type-level function: + +We apply `Nand` to `true` and `false` respectively using the `$` type-level +applicator: + +```ts +import { $, Boolean } from "hkt-toolbelt"; + +type Result = $<$, false>; // true +``` + + + +## Utility: Boolean.Nimply + +`Nimply` is a type-level function that takes in two boolean types, `T` and +`U`, and returns the boolean result of applying the 'not-implies' logical +operation on `T` and `U`. + +| Argument name | Type | Description | +| -- | -- | -- | +| T | `boolean` | A boolean type. | +| U | `boolean` | A boolean type. | + + +For example, we can use `Nimply` to determine whether two boolean types +follow the 'not-implies' logical operation. In this example, `true` and +`false` are passed as type arguments to the type-level function: + +We apply `Nimply` to `true` and `false` respectively using the `$` type-level +applicator: + +```ts +import { $, Boolean } from "hkt-toolbelt"; + +type Result = $<$, false>; // true +``` + + + +## Utility: Boolean.NorAll + +`NorAll` is a type-level function that returns true only if every element in +the given sequence of booleans is false. + +| Argument name | Type | Description | +| -- | -- | -- | +| B | `boolean[]` | A sequence of booleans. | + + +For example, we can use `NorAll` to check if none of the elements in a +boolean array are `true`. In this example, we have an array with all elements +being `false`: + +We apply `NorAll` to the boolean array using the `$` type-level applicator: + +```ts +import { $, Boolean } from "hkt-toolbelt"; + +type Result = $; // true +``` + + + +## Utility: Boolean.Nor + +`Nor` is a type-level function that takes in two boolean types, `T` and +`U`, and returns the boolean result of applying the 'nor' logical operation +on `T` and `U`. + +| Argument name | Type | Description | +| -- | -- | -- | +| T | `boolean` | A boolean type. | +| U | `boolean` | A boolean type. | + + +For example, we can use `Nor` to determine whether two boolean types are both +false. In this example, `true` and `true` are passed as type arguments to the +type-level function: + +We apply `Nor` to `true` and `true` respectively using the `$` type-level +applicator: + +```ts +import { $, Boolean } from "hkt-toolbelt"; + +type Result = $<$, true>; // false +``` + + + +## Utility: Boolean.Not + +`Not` is a type-level function that takes in a boolean type `T`, and +returns the boolean result of applying the 'not' logical operation on `T`. + +| Argument name | Type | Description | +| -- | -- | -- | +| T | `boolean` | A boolean type. | + + +For example, we can use `Not` to negate a boolean type: + +We apply `Not` to `true` using the `$` type-level applicator: + +```ts +import { $, Boolean } from "hkt-toolbelt"; + +type Result = $; // false +``` + + + +## Utility: Boolean.OrAll + +`OrAll` is a type-level function that returns true if any of the elements in +the given sequence of booleans are true. + +| Argument name | Type | Description | +| -- | -- | -- | +| T | `boolean[]` | The boolean array to check. | + + +For example, we can use `OrAll` to check if any of the elements in a +boolean array are `true`. In this example, we have an array with all elements +being `false`: + +We apply `OrAll` to the boolean array using the `$` type-level applicator: + +```ts +import { $, Boolean } from "hkt-toolbelt"; + +type Result = $; // false +``` + + + +## Utility: Boolean.Or + +`Or` is a type-level function that takes in two boolean types, `T` and +`U`, and returns the boolean result of applying the 'or' logical operation +on `T` and `U`. + +| Argument name | Type | Description | +| -- | -- | -- | +| T | `boolean` | A boolean type. | +| U | `boolean` | A boolean type. | + + +For example, we can use `Or` to determine whether at least one of two boolean +types is true. In this example, `true` and `false` are passed as type arguments +to the type-level function: + +We apply `Or` to `true` and `false` respectively using the `$` type-level +applicator: + +```ts +import { $, Boolean } from "hkt-toolbelt"; + +type Result = $<$, false>; // true +``` + + + +## Utility: Boolean.XnorAll + +`XnorAll` is a type-level function that returns true if an odd number of +elements in the given sequence of booleans are true. + +| Argument name | Type | Description | +| -- | -- | -- | +| T | `boolean[]` | The boolean array to check. | + + +For example, we can use `XnorAll` to check if an even number of elements in +a boolean array are `true`. In this example, we have an array with an odd +number of `true` elements: + +We apply `XnorAll` to the boolean array using the `$` type-level applicator: + +```ts +import { $, Boolean } from "hkt-toolbelt"; + +type Result = $; // false +``` + + + +## Utility: Boolean.Xnor + +`Xnor` is a type-level function that takes in two boolean types, `T` and +`U`, and returns the boolean result of applying the 'xnor' logical operation +on `T` and `U`. + +| Argument name | Type | Description | +| -- | -- | -- | +| T | `boolean` | A boolean type. | +| U | `boolean` | A boolean type. | + + +For example, we can use `Xnor` to determine whether two boolean types are +equal. In this example, `true` and `true` are passed as type arguments to the +type-level function: + +We apply `Xnor` to `true` and `true` respectively using the `$` type-level +applicator: + +```ts +import { $, Boolean } from "hkt-toolbelt"; + +type Result = $<$, true>; // true +``` + + +In this example, `true` and `false` are passed as type arguments to the +type-level function: + +We apply `Xnor` to `true` and `false` respectively using the `$` type-level +applicator: + +```ts +import { $, Boolean } from "hkt-toolbelt"; + +type Result = $<$, false>; // false +``` + +The 'xnor' operation is a logical operation which stands for 'exclusive nor'. +The xnor operation returns true if and only if its operands are equal. It is +equivalent to the negation of the xor (exclusive or) operation. + + + +## Utility: Boolean.Xor + +`Xor` is a type-level function that takes in two boolean types, `T` and +`U`, and returns the boolean result of applying the 'exclusive or' (xor) +logical operation on `T` and `U`. + +| Argument name | Type | Description | +| -- | -- | -- | +| T | `boolean` | A boolean type. | +| U | `boolean` | A boolean type. | + + +For example, we can use `Xor` to determine whether two boolean types are +different. In this example, `true` and `false` are passed as type arguments +to the type-level function: + +We apply `Xor` to `true` and `false` respectively using the `$` type-level +applicator: + +```ts +import { $, Boolean } from "hkt-toolbelt"; + +type Result = $<$, false>; // true +``` + +### Exclusive Or (XOR) Operation + +The 'exclusive or' operation (XOR) is a logical operation that outputs true +only when the inputs differ. In other words, it returns false when the +inputs are the same. + +Here's a truth table for the XOR operation: + +| Input A | Input B | Output | +| ------- | ------- | ------ | +| true | true | false | +| true | false | true | +| false | true | true | +| false | false | false | + +The XOR operation can also be thought of as the negation of the equality +operation (i.e., `A !== B` is equivalent to `A ^ B`). + + + +# Module: Combinator + +The `Combinator` module contains various combinators. These are higher-order +abstract functions that are applied to modify the behavior of other +type-level functions. + + + +| Utility name | Description | +| -- | -- | + | [ApplySelf](#utility-combinatorapplyself) | `ApplySelf` is a higher-order type-level function that takes in a recursive kind and applies that kind to itself. | + | [Collate](#utility-combinatorcollate) | `Collate` is a combinator that takes a number `N` and returns a type-level function of arity `N` that expects `N` arguments, and after all curried applications will return a tuple of length `N`, containing the arguments applied. | + | [FixSequence](#utility-combinatorfixsequence) | The `FixSequence` type-level function generates a fixed-point sequence for a given kind `KIND`. A fixed-point sequence is a sequence of values where the next value in the sequence is the result of applying `KIND` to the previous value, and so on, until the value reaches a fixed point. | + | [RecursiveKind](#utility-combinatorrecursivekind) | `RecursiveKind` is a higher-order type-level function that serves as a subtype. It is used to express the fact that some other higher-order kind takes in itself as a type argument. | + | [Self](#utility-combinatorself) | `Self` is a higher-order type-level function that outputs itself. Since it outputs itself, it can be applied an arbitrary amount of times. | + + +## Utility: Combinator.ApplySelf + +`ApplySelf` is a higher-order type-level function that takes in a recursive +kind and applies that kind to itself. + +This type-level function is provided only for theoretical completeness, and +experiences little practical use. + +This is similar to the `(f) => f(f)` pattern in functional programming, +where the function `f` takes in itself as an argument, and returns its own +application to itself. + +| Argument name | Type | Description | +| -- | -- | -- | +| F | `Kind` | A recursive kind that takes in itself as a type argument. | + + +For example, we can use `ApplySelf` to create the omega combinator, which +is the simplest way to cause an infinite loop in term-rewriting systems. + +```ts +import { Combinator } from "hkt-toolbelt"; + +type Omega = $; // Error +``` + + +For example, you could apply `ApplySelf` to the identity function. This +returns the identity function itself, so is of little practical use. + +```ts +import { $, Combinator, Function } from "hkt-toolbelt"; + +type Result = $; // Function.Identity +``` + + + +## Utility: Combinator.Collate + +`Collate` is a combinator that takes a number `N` and returns a type-level +function of arity `N` that expects `N` arguments, and after all curried +applications will return a tuple of length `N`, containing the arguments +applied. + +| Argument name | Type | Description | +| -- | -- | -- | +| N | `number` | The arity of the type-level function to create. | + +This is useful for creating type-level functions that are 'variadic' in the +sense that they can take in a specified number of arguments. + +Additionally, this can be used in conjunction with `Uncurry` to "lift" +arguments out of function composition. + +If zero is passed in, an empty tuple is immediately returned. + + +```ts +import { $, Kind, Type } from "ts-toolbelt" + +type Take2 = $ + +type Result = $<$, "bar"> // ["foo", "bar"] +``` + + + +## Utility: Combinator.FixSequence + +The `FixSequence` type-level function generates a fixed-point sequence for a +given kind `KIND`. A fixed-point sequence is a sequence of values where the +next value in the sequence is the result of applying `KIND` to the previous +value, and so on, until the value reaches a fixed point. + +| Argument name | Type | Description | +| -- | -- | -- | +| F | `Kind` | The kind for which the fixed-point sequence is generated. | +| X | `InputOf` | The initial value of the fixed-point sequence. | + +A fixed point is reached when applying `KIND` to a value returns that same +value. Notably, this means that an infinite loop is possible if we do not +converge to a fixed point. + +There are two scenarios where we do not reach convergence: +- If we diverge (generate larger and larger values). +- If we oscillate (generate values that infinitely cycle between values). + +If convergence is not reached, the 'infinite type instantiation' error will +be emitted by the TypeScript compiler. + +### Term Rewriting + +Here we show a simple example of a convergent fixed-point sequence. Term +rewriting is a concept in computer science that is used to transform a +string into another string. + +We define a term rule "xyz --> x", which replaces the string "xyz" with the +string "x". We then create a fixed-point sequence for this term rule. + +A term sequence may be terminal or non-terminal. A terminal term sequence is +one where we reach a state where no more term rules can be applied. + +```ts +import { $, Function, String, Combinator } from "hkt-toolbelt"; + +type Rewrite = $, "x">> + +// ["zyxyzyzyz", "zyxyzyz", "zyxyz", "zyx"] +type Result = $ +``` + +In the above example, we started with a given string and applied successive +term rules until we reached a terminal state. + +### Divergent Case + +Here we show a simple example of a divergent fixed-point sequence. We define +the (+1) type-level function, which takes a number and returns that number +plus 1. We then create a fixed-point sequence for (+1), starting from the +value `0`. + +```ts +import { $, Combinator, NaturalNumber } from "hkt-toolbelt"; + +// Error: Type instantiation is excessively deep and possibly infinite. +type Result = $<$>, 0>; +``` + +In the above example, we started with the value `0` and applied the (+1) +function to it. The result of applying (+1) to `0` is `1`. We then apply (+1) +to `1`, which results in `2`. We continue this process until we reach the +maximum number of iterations allowed by the TypeScript compiler. + + + +## Utility: Combinator.RecursiveKind + +`RecursiveKind` is a higher-order type-level function that serves as a +subtype. It is used to express the fact that some other higher-order kind +takes in itself as a type argument. + +| Argument name | Type | Description | +| -- | -- | -- | +| F | `RecursiveKind` | Input type of the recursive kind. | + +This type-level function doesn't do much on its own, but it is useful in +combination with other type-level functions. + + + +## Utility: Combinator.Self + +`Self` is a higher-order type-level function that outputs itself. Since it +outputs itself, it can be applied an arbitrary amount of times. + +| Argument name | Type | Description | +| -- | -- | -- | +| X | `any` | An ignored input type. | + + +```ts +import { $, Combinator } from "hkt-toolbelt"; + +type Self1 = $; + +type Self2 = $; +``` + + + +# Module: Conditional + +The `Conditional` module contains various conditional type utilities. These +utilities are used to express conditional logic in type-level programming. + + +```ts +import { $, Conditional } from 'hkt-toolbelt' + +type MyFcn = $<$, 'foo'>, 'bar'> + +type Result = $ // 'foo' +type Result2 = $ // 'bar' +``` + + +| Utility name | Description | +| -- | -- | + | [EqualsAll](#utility-conditionalequalsall) | `EqualsAll` is a type-level function that takes in one array of types, `T`, and returns a type-level function that returns `true` if all elements of `T` evaluate to the same type or `T` is empty, and `false` if otherwise. | + | [Equals](#utility-conditionalequals) | `Equals` is a type-level function that takes in one type, `T`, and returns a type-level function that takes in one type, `U`, and returns `true` if `U` is the same type as `T`, and `false` otherwise. | + | [ExtendsAll](#utility-conditionalextendsall) | `ExtendsAll` is a type-level function that takes in a type `U` and an array of types, `T`, and returns a type-level function that returns `true` if all elements of `T` extend `U`, and `false` if otherwise. | + | [Extends](#utility-conditionalextends) | `Extends` is a type-level function that takes in two types, `T` and `U`, and returns a boolean that represents whether `T` extends `U`. | + | [If](#utility-conditionalif) | `If` is a type-level if-then-else statement. Given a predicate `Predicate`, a true branch `Then`, and a false branch `Else`, `If` will evaluate the predicate with an input `X` of type `Kind._$inputOf`. If the predicate returns `true`, then `If` will return the result of applying `Then` to `X`. Otherwise, `If` will return the result of applying `Else` to `X`. | + | [IsSupertypeOf](#utility-conditionalissupertypeof) | `IsSupertypeOf` is a type-level function that takes in two types, `T` and `U`, and returns a boolean that represents whether `T` is a supertype of `U`. | + | [NotEquals](#utility-conditionalnotequals) | `NotEquals` is a type-level function that returns `true` if `T` and `U` are not equal. Otherwise, it returns `false`. | + + +## Utility: Conditional.EqualsAll + +`EqualsAll` is a type-level function that takes in one array of types, `T`, and returns a +type-level function that returns `true` if all elements of `T` evaluate to the same type or `T` is empty, +and `false` if otherwise. + +| Argument name | Type | Description | +| -- | -- | -- | +| T | `any[]` | An array of types. | + + +For example, we can use `EqualsAll` to determine whether multiple types are equal. +In this example, `EqualsAll` is a type-level function that returns `true` if all elements of its input evaluate as being equal. + +We apply this type-level function to `[false, false, false]` and `[true, false]` respectively using the `$` type-level applicator: + +```ts +import { $, Conditional } from "hkt-toolbelt"; + +type IsTrue = $; // true +type IsNotTrue = $; // false +``` + + + +## Utility: Conditional.Equals + +`Equals` is a type-level function that takes in one type, `T`, and returns a +type-level function that takes in one type, `U`, and returns `true` if `U` is +the same type as `T`, and `false` otherwise. + +| Argument name | Type | Description | +| -- | -- | -- | +| T | `any` | A type. | +| U | `any` | A type. | + + +For example, we can use `Equals` to determine whether two types are equal. +In this example, we partially apply `Equals` to `true`, which results in a +type-level function that returns `true` if its input is the same as `true`. + +We then apply this partially applied function to `true` and `false` +respectively using the `$` type-level applicator: + +```ts +import { $, Conditional } from "hkt-toolbelt"; + +type IsTrue = $<$, true>; // true +type IsNotTrue = $<$, false>; // false +``` + + + +## Utility: Conditional.ExtendsAll + +`ExtendsAll` is a type-level function that takes in a type `U` and an array of types, `T`, +and returns a type-level function that returns `true` if all elements of `T` extend `U`, +and `false` if otherwise. + +If T is empty, `true` is returned. + +| Argument name | Type | Description | +| -- | -- | -- | +| U | `any` | A type. | +| T | `any[]` | An array of types. | + + +For example, we can use `ExtendsAll` to determine whether a series of types all extend a second input type. +In this example, we partially apply `ExtendsAll` to `string | number` and `never`, which result in +two type-level functions that return `true` if all elements of their input extend `string | number` and `never`, respectively. + +We then apply both of these partially applied functions to `[string, number]` using the `$` type-level applicator. + +```ts +import { $, Conditional } from "hkt-toolbelt"; + +type IsTrue = $<$, [string, number]>; // true +type IsNotTrue = $<$, [string, number]>; // false +``` + + + +## Utility: Conditional.Extends + +`Extends` is a type-level function that takes in two types, `T` and `U`, and +returns a boolean that represents whether `T` extends `U`. + +| Argument name | Type | Description | +| -- | -- | -- | +| T | `any` | The supertype that we are checking if `U` extends. | +| U | `any` | The type that we are checking if it is a subtype of `T`. | + + +For example, we can use `Extends` to determine whether a type `T` extends a +type `U`. In this example, we test whether `true` extends `boolean`: + +We apply `Extends` to `boolean` and `true` respectively using the `$` +type-level applicator. This checks whether `true` extends `boolean`: + +```ts +import { $, Conditional } from "hkt-toolbelt"; + +type Result = $<$, true>; // true +``` + +In the following examples, we test whether a string extends a number: + +```ts +import { $, Conditional } from "hkt-toolbelt"; + +type Result = $<$, string>; // false +``` + +Note that TypeScript provides its own `extends` keyword that can be used to +perform a subtype check. However, `extends` can only be used in a +conditional type. `Extends` is composable, so it can be used in more +sophisticated type-level functions. + + + +## Utility: Conditional.If + +`If` is a type-level if-then-else statement. Given a predicate `Predicate`, +a true branch `Then`, and a false branch `Else`, `If` will evaluate the +predicate with an input `X` of type `Kind._$inputOf`. If the +predicate returns `true`, then `If` will return the result of applying +`Then` to `X`. Otherwise, `If` will return the result of applying `Else` +to `X`. + +This can be thought of as a type-level ternary operator. + +| Argument name | Type | Description | +| -- | -- | -- | +| Predicate | `Kind` | A type-level function that returns a boolean. | +| Then | `Kind` | A type-level function that is applied when the predicate returns | +| Else | `Kind` | A type-level function that is applied when the predicate returns | +| X | `InputOf` | The input to the predicate function. | + +## Usage Examples + + +For example, we can use `If` to create a type-level ternary operator. Since +`If` has a high arity, we use `$N` to pipe multiple arguments to `If`. + +Let's implement a function that emits 'yes' if the input string starts with +'foo', and 'no' otherwise: + +```ts +import { $, Conditional, Function } from "hkt-toolbelt"; + +type StartsWithFoo = $N< + Conditional.If, + [ + $, + $, + $ + ] +>; + +type Result = StartsWithFoo<"foo">; // "yes" +``` + +In this example, we use `String.StartsWith` to create a predicate function +that returns `true` if the input string starts with "foo", and `false` +otherwise. + +Each of the truthy and falsy branches are simple constant functions that +return the string "yes" and "no", respectively. These functions are applied +on the input string, so more complex processing can be done in the branches. + + +We can also use `If` to filter a list. In this example, we use +`String.StartsWith` to filter out elements of a list that do not start with +the string "foo": + +```ts +import { $, Conditional, List, String } from "hkt-toolbelt"; + +type Filtered = $< + $< + List.Filter, + $, String.Identity> + >, + ["foo", "bar", "baz", "foobar"] +>; // ["foo", "foobar"] +``` + +Here, we use `If` to create a conditional type-level function that returns +`String.Identity` when the string starts with "foo", and `never` otherwise. +We then pass this function to `List.Filter`, which returns a list of only the +elements that satisfy the predicate. + + + +## Utility: Conditional.IsSupertypeOf + +`IsSupertypeOf` is a type-level function that takes in two types, `T` and `U`, and +returns a boolean that represents whether `T` is a supertype of `U`. + +This function checks the converse of `Extends`. +While `Extends` returns `true` if `T` -> `U` is true, +`IsSupertypeOf` will return `true` if and only if `T` <- `U` is true. + +This is useful if it is known that `U` extends `T`, +but the two arguments are being supplied in the opposite order expected by `Extends`. + +| Argument name | Type | Description | +| -- | -- | -- | +| T | `any` | The supertype that we are checking if `U` extends. | +| U | `any` | The type that we are checking if it is a subtype of `T`. | + + +For example, we can use `IsSupertypeOf` to determine whether a given type `T` is a supertype of +another type `U`. In this example, we test whether `boolean` is a supertype of `true`: + +We apply `IsSupertypeOf` to `true` and `boolean` respectively using the `$` +type-level applicator. This checks whether `boolean` is a supertype of `true`: + +```ts +import { $, Conditional } from "hkt-toolbelt"; + +type Result = $<$, boolean>; // true +``` + + +In the following examples, we test whether a number is a supertype of a string: + +```ts +import { $, Conditional } from "hkt-toolbelt"; + +type Result = $<$, string>; // false +``` + +TypeScript does not provide a native keyword like `extends` that can be used to +perform a supertype check. While `extends` can only be used in a +conditional type, `IsSupertypeOf` is composable, so it can be used in more +sophisticated type-level functions. + + + +## Utility: Conditional.NotEquals + +`NotEquals` is a type-level function that returns `true` if `T` and `U` are +not equal. Otherwise, it returns `false`. + +| Argument name | Type | Description | +| -- | -- | -- | +| T | `any` | The first type to compare. | +| U | `any` | The second type to compare. | + + +```ts +import { $, Conditional } from 'hkt-toolbelt' + +type Result = $ // true +``` + + + +# Module: Digit + +The `Digit` module contains various utilities for working with decimal digits +(0-9). Digits are used in various contexts, such as representing numbers. + + +```ts +import { $, Digit } from 'hkt-toolbelt' + +type Result = $<$, 2> // 3 +``` + + +| Utility name | Description | +| -- | -- | + | [AddTens](#utility-digitaddtens) | `AddTens` is a type-level function that takes two decimal digit types, `A` and `B`, adds them together, and returns the resultant tens digit. | + | [Add](#utility-digitadd) | `Add` is a type-level function that takes two decimal digit types, `A` and `B`, adds them together (excluding the carry-over), and returns the resulting digit type. | + | [Compare](#utility-digitcompare) | `Compare` is a type-level function that takes two decimal digit types, `A` and `B`, compares their magnitudes, and returns the corresponding result {-1, 0, or 1}. | + | [DecrementTens](#utility-digitdecrementtens) | `DecrementTens` is a type-level function that takes a single decimal digit type `A` and determines whether the tens digit should be decremented during a subtraction operation. | + | [Decrement](#utility-digitdecrement) | `Decrement` is a type-level function which takes in a required `Digit.Digit`, and returns the preceding digit. The preceding digit is the digit immediately before the provided digit in the sequence "0, 1, 2, 3, 4, 5, 6, 7, 8, 9". | + | [Digit](#utility-digitdigit) | `Digit` is a type alias that represents a single decimal digit in the range from "0" to "9" (inclusive). Each decimal digit is represented as a string literal type. This type is particularly useful when working with type-level numerical operations or string manipulation involving numbers. | + | [IncrementTens](#utility-digitincrementtens) | `IncrementTens` is a type-level function that takes a digit type `A` as input and returns the tens place increment for that digit. | + | [Increment](#utility-digitincrement) | `Increment` is a type-level function that takes in a digit type `A` and returns the next digit in the sequence. If the input digit is "9", the function returns "0". | + | [MultiplyTens](#utility-digitmultiplytens) | `MultiplyTens` is a type-level function that takes in two single-digit types, `A` and `B`, and returns the tens place of the product of `A` and `B`. | + | [Multiply](#utility-digitmultiply) | `Multiply` is a type-level function that takes in two digit types, `A` and `B`, and returns the result of multiplying `A` by `B`, modulo 10. The result is a single digit type. | + | [SubtractTens](#utility-digitsubtracttens) | `SubtractTens` is a type-level function that takes in two digit types, `A` and `B`, and returns the result of subtracting `B` from `A` in the tens place. If `B` is greater than `A`, the result is 1. | + | [Subtract](#utility-digitsubtract) | `Subtract` is a type-level function that takes in two digit types, `A` and `B`, and returns the digit result of subtracting `B` from `A`. | + | [Zero](#utility-digitzero) | `Zero` is a type representing the digit zero ("0"). It is a subtype of the `Digit` type, and can be used in various arithmetic operations and comparisons provided by the `DigitList` and `NaturalNumber` namespaces. | + + +## Utility: Digit.AddTens + +`AddTens` is a type-level function that takes two decimal digit types, +`A` and `B`, adds them together, and returns the resultant tens digit. + +| Argument name | Type | Description | +| -- | -- | -- | +| A | `Digit` | A one-character decimal digit type. | +| B | `Digit` | A one-character decimal digit type. | + + +For example, using the `hkt-toolbelt` `$` type-level applicator, +we apply `AddTens` to the digits `5` and `7`: + +```ts +import { Kind, $, Digit } from "hkt-toolbelt"; + +type Result = $<$, "7">; // "1" +``` + + + +## Utility: Digit.Add + +`Add` is a type-level function that takes two decimal digit types, +`A` and `B`, adds them together (excluding the carry-over), and returns +the resulting digit type. + +| Argument name | Type | Description | +| -- | -- | -- | +| A | `Digit` | A one-character decimal digit type. | +| B | `Digit` | A one-character decimal digit type. | + + +For example, using the `hkt-toolbelt` `$` type-level applicator, +we apply `Add` to the digits `7` and `4`: + +```ts +import { Kind, $, Digit } from "hkt-toolbelt"; + +type Result = $<$, "4">; // "1" +``` + + + +## Utility: Digit.Compare + +`Compare` is a type-level function that takes two decimal digit types, `A` +and `B`, compares their magnitudes, and returns the corresponding result +{-1, 0, or 1}. + +| Argument name | Type | Description | +| -- | -- | -- | +| A | `Digit` | A one-character decimal digit type. | +| B | `Digit` | A one-character decimal digit type. | + + +For example, we can use the `$` type-level applicator to apply `Compare` to +two digits. In this example, we compare the digits `7` and `4`. + +```ts +import { Kind, $, Digit } from "hkt-toolbelt" + +type Result = $<$, "4"> // 1 +``` + + + +## Utility: Digit.DecrementTens + +`DecrementTens` is a type-level function that takes a single decimal digit +type `A` and determines whether the tens digit should be decremented +during a subtraction operation. + +| Argument name | Type | Description | +| -- | -- | -- | +| A | `Digit` | A one-character decimal digit type. | + + +For example, using the `hkt-toolbelt` `$` type-level applicator, we apply +`DecrementTens` to the digit `4`: + +```ts +import { $, Digit } from "hkt-toolbelt" + +type Result = $ // "0" +``` + + + +## Utility: Digit.Decrement + +`Decrement` is a type-level function which takes in a required `Digit.Digit`, +and returns the preceding digit. The preceding digit is the digit immediately +before the provided digit in the sequence "0, 1, 2, 3, 4, 5, 6, 7, 8, 9". + +We apply `Decrement` to a digit using the `$` type-level applicator. + +| Argument name | Type | Description | +| -- | -- | -- | +| A | `Digit` | A single-digit type which represents a digit from "0" to "9". | + + +For example, if we want to subtract one from the digit "5", we would use +this type-level function as follows: + +```ts +import { $, Digit } from 'hkt-toolbelt'; + +type Result = $ // "4" +``` + + + +## Utility: Digit.Digit + +`Digit` is a type alias that represents a single decimal digit in the range +from "0" to "9" (inclusive). Each decimal digit is represented as a string +literal type. This type is particularly useful when working with +type-level numerical operations or string manipulation involving numbers. + + + + +## Utility: Digit.IncrementTens + +`IncrementTens` is a type-level function that takes a digit type `A` as +input and returns the tens place increment for that digit. + +| Argument name | Type | Description | +| -- | -- | -- | +| A | `Digit` | A digit type. | + + +We apply `IncrementTens` to a digit using the `$` type-level applicator: + +```ts +import { $, Digit } from "hkt-toolbelt"; + +type Result = $; // "1" +``` + + + +## Utility: Digit.Increment + +`Increment` is a type-level function that takes in a digit type `A` and +returns the next digit in the sequence. If the input digit is "9", the +function returns "0". + +| Argument name | Type | Description | +| -- | -- | -- | +| A | `Digit` | A digit type. | + + +For example, we can use `Increment` to increment a digit type: + +We apply `Increment` to a digit type using the `$` type-level applicator: + +```ts +import { $, Digit } from "hkt-toolbelt" + +type Result = $ // "4" +``` + + + +## Utility: Digit.MultiplyTens + +`MultiplyTens` is a type-level function that takes in two single-digit +types, `A` and `B`, and returns the tens place of the product of `A` and `B`. + +| Argument name | Type | Description | +| -- | -- | -- | +| A | `Digit` | A single-digit type. | +| B | `Digit` | A single-digit type. | + + +For example, we can use `MultiplyTens` to compute the tens place of the +product of two single-digit types: + +We apply `MultiplyTens` to `"5"` and `"4"` respectively using the `$` +type-level applicator: + +```ts +import { $, Digit } from "hkt-toolbelt" + +type Result = $<$, "4"> // "2" +``` + + + +## Utility: Digit.Multiply + +`Multiply` is a type-level function that takes in two digit types, `A` and +`B`, and returns the result of multiplying `A` by `B`, modulo 10. The result +is a single digit type. + +| Argument name | Type | Description | +| -- | -- | -- | +| A | `Digit` | A digit type, the multiplier. | +| B | `Digit` | A digit type, the multiplicand. | + + +For example, we can use `Multiply` to multiply two digit types. In this +example, `2` and `3` are passed as type arguments to the type-level function: + +We apply `Multiply` to `2` and `3` respectively using the `$` type-level +applicator: + +```ts +import { $, Digit } from "hkt-toolbelt" + +type Result = $<$, "3"> // "6" +``` + + + +## Utility: Digit.SubtractTens + +`SubtractTens` is a type-level function that takes in two digit types, `A` +and `B`, and returns the result of subtracting `B` from `A` in the tens +place. If `B` is greater than `A`, the result is 1. + +| Argument name | Type | Description | +| -- | -- | -- | +| A | `Digit` | A digit type, the minuend. | +| B | `Digit` | A digit type, the subtrahend. | + + +For example, we can use `SubtractTens` to subtract two digit types in the +tens place: + +We apply `SubtractTens` to `"2"` and `"9"` respectively using the `$` +type-level applicator: + +```ts +import { $, Digit } from "hkt-toolbelt" + +type Result = $<$, "9"> // "1" +``` + + + +## Utility: Digit.Subtract + +`Subtract` is a type-level function that takes in two digit types, `A` and +`B`, and returns the digit result of subtracting `B` from `A`. + +| Argument name | Type | Description | +| -- | -- | -- | +| A | `Digit` | A digit type, the minuend. | +| B | `Digit` | A digit type, the subtrahend. | + + +For example, we can use `Subtract` to subtract two digit types. In this +example, "2" and "1" are passed as type arguments to the type-level function: + +We apply `Subtract` to "2" and "1" respectively using the `$` type-level +applicator: + +```ts +import { $, Digit } from "hkt-toolbelt" + +type Result = $<$, "1"> // "1" +``` + + + +## Utility: Digit.Zero + +`Zero` is a type representing the digit zero ("0"). It is a subtype of the +`Digit` type, and can be used in various arithmetic operations and +comparisons provided by the `DigitList` and `NaturalNumber` namespaces. + + +For example, we can use `Zero` in arithmetic operations like addition: + +```ts +import { $, Digit } from "hkt-toolbelt"; + +type Result = $<$, "2">; // "3" +``` + +In this example, we add `Zero` to the digit "1", and the result is a digit +list containing the digit "1". + + + +# Module: DigitList + +The `DigitList` module contains various utilities for working with digit +lists. Digit lists are a type-level representation of lists of decimal digits +(0-9). They are used in various contexts, such as representing numbers. + + +```ts +import { $, DigitList } from 'hkt-toolbelt' + +type Result = $<$, ["4", "5", "6"]> // ["5", "7", "9"] +``` + + +| Utility name | Description | +| -- | -- | + | [Add](#utility-digitlistadd) | `Add` is a type-level function that takes in two digit lists `A` and `B`, and returns the sum of the two digit lists as a new digit list. | + | [Compare](#utility-digitlistcompare) | `Compare` is a type-level function that takes in two digit lists `A` and `B`, and returns the comparison result as a number type. The result will be 1 if `A` is greater than `B`, 0 if `A` is equal to `B`, and -1 if `A` is less than `B`. | + | [Decrement](#utility-digitlistdecrement) | `Decrement` is a type-level function that takes in a digit list `A` and returns a new digit list representing the result of decrementing the input digit list by 1. If the input digit list is empty or represents zero, the result will be a digit list representing zero. | + | [DigitList](#utility-digitlistdigitlist) | `DigitList` is a type alias representing a list of decimal digits from "0" to "9" (inclusive). | + | [DivideBySubtraction](#utility-digitlistdividebysubtraction) | `DivideBySubtraction` is a type-level function that performs a division by subtraction. It returns the result of the division. | + | [Divide](#utility-digitlistdivide) | `Divide` is a type-level function that performs a division operation. It returns the result of the division operation. | + | [First](#utility-digitlistfirst) | `First` is a type-level function that returns the first digit of a digit list. It returns the first digit of the digit list. If the list is empty, it returns ["0"]. | + | [FromString](#utility-digitlistfromstring) | `FromString` is a type-level function that converts a string into a digit list and trims leading zeros. It returns a digit list from a string. | + | [Increment](#utility-digitlistincrement) | `Increment` is a type-level function that increments a digit list. It returns the incremented digit list. | + | [IsEven](#utility-digitlistiseven) | `IsEven` is a type-level function that checks if a digit list is even. It returns `true` if the digit list is even, `false` otherwise. | + | [IsOdd](#utility-digitlistisodd) | `IsOdd` is a type-level function that checks if a digit list is odd. It returns a function that takes a digit list as a parameter and returns `true` if the digit list is odd, `false` otherwise. | + | [Last](#utility-digitlistlast) | `Last` is a type-level function that gets the last digit of a digit list. It returns the last digit of the digit list. If the list is empty, it returns "0". | + | [Modulo](#utility-digitlistmodulo) | `Modulo` is a type-level function that calculates the modulo of two digit lists. Returns the result of the modulo operation. | + | [MultiplyDigit](#utility-digitlistmultiplydigit) | `MultiplyDigit` is a type-level function that multiplies a digit list by a single digit. | + | [Multiply](#utility-digitlistmultiply) | `Multiply` is a type-level function that multiplies a digit list by another digit list. It returns the result of the multiplication operation. | + | [Pop](#utility-digitlistpop) | `Pop` is a type-level function that removes the last digit from a digit list. It returns the digit list after the last digit has been removed. This may result in a completely empty digit list, which is semantically equivalent to the number zero. | + | [Shift](#utility-digitlistshift) | `Shift` is a type-level function that removes the first digit from a digit list. It returns the result of the shift operation. | + | [Subtract](#utility-digitlistsubtract) | `Subtract` is a type-level function that subtracts one digit list from another. It returns the result of the subtraction. | + | [ToNumber](#utility-digitlisttonumber) | `ToNumber` is a type-level function that represents a function to convert a digit list to a number. It returns the number from the digit list. | + | [ToString](#utility-digitlisttostring) | `ToString` is a type-level function that converts a digit list to a string. It returns the string representation of the digit list. | + | [TrimRight](#utility-digitlisttrimright) | `TrimRight` is a type-level function that trims trailing zeros from a digit list. It returns the trimmed digit list. | + | [Trim](#utility-digitlisttrim) | `Trim` is a type-level function that trims leading zeros from a digit list. It returns the trimmed digit list. | + + +## Utility: DigitList.Add + +`Add` is a type-level function that takes in two digit lists `A` and `B`, +and returns the sum of the two digit lists as a new digit list. + +| Argument name | Type | Description | +| -- | -- | -- | +| A | | A digit list. | +| B | | A digit list. | + + +For example, we can use `Add` to add two digit lists representing the +numbers 123 and 456: + +We apply `Add` to `["1", "2", "3"]` and `["4", "5", "6"]` respectively using +the `$` type-level applicator: + +```ts +import { $, DigitList } from "hkt-toolbelt" + +type Result = $<$, ["4", "5", "6"]> // ["5", +"7", "9"] +``` + + + +## Utility: DigitList.Compare + +`Compare` is a type-level function that takes in two digit lists `A` and +`B`, and returns the comparison result as a number type. The result will be +1 if `A` is greater than `B`, 0 if `A` is equal to `B`, and -1 if `A` is +less than `B`. + +| Argument name | Type | Description | +| -- | -- | -- | +| A | | A digit list type. | +| B | | A digit list type. | + + + +For example, we can use the `$` type-level applicator to apply `Compare` to +two digit lists. + +In this example, we compare the digit lists ["1", "2", "3"] and ["3", "2", +"1"]: + +```ts +import { $, DigitList } from "hkt-toolbelt" + +type Result = $<$, ["3", "2", "1"]> // -1 +``` + + + +## Utility: DigitList.Decrement + +`Decrement` is a type-level function that takes in a digit list `A` and +returns a new digit list representing the result of decrementing the input +digit list by 1. If the input digit list is empty or represents zero, the +result will be a digit list representing zero. + +| Argument name | Type | Description | +| -- | -- | -- | +| A | | A digit list type. | + + +For example, we can use `Decrement` to decrement a digit list representing +the number 42 by 1. In this example, the digit list `["4", "2"]` is passed as +a type argument to the type-level function: + +```ts +import { $, DigitList } from "hkt-toolbelt"; + +type Result = $; // ["4", "1"] +``` + + +We can also use `Decrement` with an empty digit list or a digit list +representing zero. In both cases, the result will be a digit list +representing zero: + +```ts +import { $, DigitList } from "hkt-toolbelt"; + +type Result1 = $; // ["0"] +type Result2 = $; // ["0"] +``` + + + +## Utility: DigitList.DigitList + +`DigitList` is a type alias representing a list of decimal digits from "0" +to "9" (inclusive). + + +For example, we can use `DigitList` to represent a list of decimal digits from "0" to "9": + +```ts +import { DigitList } from "hkt-toolbelt"; + +type MyDigitList = DigitList; // ("0" | "1" | "2" | ... | "9")[] +``` + + + +## Utility: DigitList.DivideBySubtraction + +`DivideBySubtraction` is a type-level function that performs a division by subtraction. +It returns the result of the division. + +| Argument name | Type | Description | +| -- | -- | -- | +| A | | A digit list representing a number to divide. | +| B | | A digit list representing a number to divide by. | + + +For example, we can use `DivideBySubtraction` to divide a digit list representing the number 10 by 2: + +```ts +import { $, DigitList } from "hkt-toolbelt"; + +type Result = $<$, ["2"]>; // ["5"] quotient is 5, and the remainder is 0. +``` + + + +## Utility: DigitList.Divide + +`Divide` is a type-level function that performs a division operation. +It returns the result of the division operation. + + +For example, we can use `Divide` to create a division operation that divides a digit list representing the number 10 by 2: + +```ts +import { $, DigitList } from "hkt-toolbelt"; + +type Result = $<$, ["2"]>; // ["5"] +``` + +In this example, `Result` is a type that represents the digit list ["5"], which is the result of dividing 10 by 2. + + + +## Utility: DigitList.First + +`First` is a type-level function that returns the first digit of a digit list. +It returns the first digit of the digit list. If the list is empty, it returns ["0"]. + + +For example, we can use `First` to get the first digit of a digit list representing the number 12: + +```ts +import { $, DigitList, Type } from "hkt-toolbelt"; + +type Result = $; // "1" +``` + +In this example, `Result` is a type that represents the digit "1", which is the first digit of the digit list ["1", "2"]. + + + +## Utility: DigitList.FromString + +`FromString` is a type-level function that converts a string into a digit list and trims leading zeros. +It returns a digit list from a string. + +| Argument name | Type | Description | +| -- | -- | -- | +| A | | The string to be converted into a digit list. | + + +For example, we can use `FromString` to convert a string into a digit list: + +```ts +import { $, DigitList } from "hkt-toolbelt"; + +type Result = $; // ["1", "2", "3"] +``` + + +Also we can use `FromString` to convert a string into a digit list and trim leading zeros. + +```ts +import { $, DigitList, Type } from "hkt-toolbelt"; + +type Result = $; // ["1", "2", "3"] +``` + + + +## Utility: DigitList.Increment + +`Increment` is a type-level function that increments a digit list. +It returns the incremented digit list. + +| Argument name | Type | Description | +| -- | -- | -- | +| A | | The digit list to increment. | + + +For example, we can use `Increment` to increment a digit list: + +```ts +import { $, DigitList, Type } from "hkt-toolbelt"; + +type Result = $; // ["1", "1"] +``` + +In this example, `Result` is a type that represents the digit list ["1", "1"], which is the result of incrementing the digit list ["1", "0"]. + + + +## Utility: DigitList.IsEven + +`IsEven` is a type-level function that checks if a digit list is even. +It returns `true` if the digit list is even, `false` otherwise. + +| Argument name | Type | Description | +| -- | -- | -- | +| T | | The digit list to check. | + + +For example, we can use `IsEven` to check if a digit list is even: + +```ts +import { $, DigitList } from "hkt-toolbelt"; + +type Result = $; // true +``` + +In this example, `Result` is a type that represents `true`, which indicates that the digit list ["1", "0"] is even. + + + +## Utility: DigitList.IsOdd + +`IsOdd` is a type-level function that checks if a digit list is odd. +It returns a function that takes a digit list as a parameter and returns `true` if the digit list is odd, `false` otherwise. + +| Argument name | Type | Description | +| -- | -- | -- | +| T | | The digit list to check. | + + +For example, we can use `IsOdd` to check if a digit list is odd: + +```ts +import { $, DigitList } from "hkt-toolbelt"; + +type Result = $; // false +``` + +In this example, `Result` is a type that represents `false`, which indicates that the digit list ["1", "0"] is not odd. + + + +## Utility: DigitList.Last + +`Last` is a type-level function that gets the last digit of a digit list. +It returns the last digit of the digit list. If the list is empty, it returns "0". + +| Argument name | Type | Description | +| -- | -- | -- | +| A | | The digit list to get the last digit from. | + + +For example, we can use `Last` to get the last digit of a digit list: + +```ts +import { $, DigitList } from "hkt-toolbelt"; + +type Result = $; // "3" +``` + +In this example, `Result` is a type that represents "3", which is the last digit of the digit list ["1", "2", "3"]. + + + +## Utility: DigitList.Modulo + +`Modulo` is a type-level function that calculates the modulo of two digit lists. +Returns the result of the modulo operation. + +| Argument name | Type | Description | +| -- | -- | -- | +| A | | The first digit list. | +| B | | The second digit list. | + + +For example, we can use `Modulo` to calculate the modulo of two digit lists: + +```ts +import { $, DigitList } from "hkt-toolbelt"; + +type Result = $<$, ["3"]>; // ["1"] +``` + +In this example, `Result` is a type that represents ["1"], which is the modulo of the division of ["1", "0"] by ["3"]. + + + +## Utility: DigitList.MultiplyDigit + +`MultiplyDigit` is a type-level function that multiplies a digit list by a +single digit. + +Returns the result of the multiplication operation. + +| Argument name | Type | Description | +| -- | -- | -- | +| A | | The digit list. | +| B | | The single digit. | + + +For example, we can use `MultiplyDigit` to multiply a digit list by a single +digit: + +```ts +import { $, DigitList } from "hkt-toolbelt"; + +type Result = $<$, ["3"]>; // ["6"] +``` + +In this example, `Result` is a type that represents ["6"], which is the +result of multiplying ["3"] by "2". + + + +## Utility: DigitList.Multiply + +`Multiply` is a type-level function that multiplies a digit list by another digit list. +It returns the result of the multiplication operation. + +| Argument name | Type | Description | +| -- | -- | -- | +| A | | The digit list. | +| B | | The single digit. | + + +For example, we can use `Multiply` to multiply a digit list ["4", "2"] by another digit list ["1", "2"]: + +```ts +import { $, DigitList } from "hkt-toolbelt"; + +type Is504 = $<$, ["4", "2"]>; // ["5", "0", "4"] +``` + + +If one of the inputs is an empty digit list or the zero digit, the result will be the zero digit. + +```ts +import { DigitList } from "hkt-toolbelt"; + +type IsZero = $<$, ["4", "2"]>; // ["0"] +type IsZero2 = $<$; // ["0"] +``` + + + +## Utility: DigitList.Pop + +`Pop` is a type-level function that removes the last digit from a digit list. +It returns the digit list after the last digit has been removed. This may +result in a completely empty digit list, which is semantically equivalent to +the number zero. + +| Argument name | Type | Description | +| -- | -- | -- | +| A | | The digit list. | + + +For example, we can use `Pop` to remove the last digit from a digit list: + +```ts +import { $, DigitList, Type } from "hkt-toolbelt"; + +type Result = $; // ["1", "2"] +``` + +In this example, `Result` is a type that represents ["1", "2"], which is the result of removing the last digit from ["1", "2", "3"]. + + + +## Utility: DigitList.Shift + +`Shift` is a type-level function that removes the first digit from a digit list. +It returns the result of the shift operation. + + +For example, we can use `Shift` to remove the first digit from a digit list: + +```ts +import { $, DigitList } from "hkt-toolbelt"; + +type Result = $; // ["2", "3"] +``` + +In this example, `Result` is a type that represents ["2", "3"], which is the result of removing the first digit from ["1", "2", "3"]. + + + +## Utility: DigitList.Subtract + +`Subtract` is a type-level function that subtracts one digit list from +another. It returns the result of the subtraction. + +| Argument name | Type | Description | +| -- | -- | -- | +| A | | A digit list representing a number to subtract. | +| B | | A digit list representing a number to subtract by. | + + +For example, we can use `Subtract` to subtract one digit list from another: + +```ts +import { $, DigitList } from "hkt-toolbelt"; + +type Result = $; // ["2", "5"] +``` + +In this example, `Result` is a type that represents ["2", "5"], which is the +result of subtracting ["2", "5"] from ["5", "0"]. + + + +## Utility: DigitList.ToNumber + +`ToNumber` is a type-level function that represents a function to convert a digit list to a number. +It returns the number from the digit list. + +| Argument name | Type | Description | +| -- | -- | -- | +| x | | A digit list to convert to a number. | + + +For example, we can use `ToNumber` to convert a digit list to a number: + +```ts +import { $, DigitList } from "hkt-toolbelt"; + +type Result = $; // 502 +``` + +In this example, `Result` is a type that represents the number 502, which is the result of converting the digit list ["5", "0", "2"] to a number. + + + +## Utility: DigitList.ToString + +`ToString` is a type-level function that converts a digit list to a string. +It returns the string representation of the digit list. + +| Argument name | Type | Description | +| -- | -- | -- | +| A | | A digit list to convert to a string. | + + +For example, we can use `ToString` to convert a digit list to a string: + +```ts +import { $, DigitList } from "hkt-toolbelt"; + +type Result = $; // "502" +``` + +In this example, `Result` is a type that represents the string "502", which is the result of converting the digit list ["5", "0", "2"] to a string. + + + +## Utility: DigitList.TrimRight + +`TrimRight` is a type-level function that trims trailing zeros from a digit list. +It returns the trimmed digit list. + +| Argument name | Type | Description | +| -- | -- | -- | +| x | | A digit list to trim trailing zeros from. | + + +For example, we can use `TrimRight` to trim trailing zeros from a digit list: + +```ts +import { $, DigitList } from "hkt-toolbelt"; + +type Result = $; // ["3"] +``` + + + +## Utility: DigitList.Trim + +`Trim` is a type-level function that trims leading zeros from a digit list. +It returns the trimmed digit list. + +| Argument name | Type | Description | +| -- | -- | -- | +| x | | A digit list to trim leading zeros from. | + + +For example, we can use `Trim` to trim leading zeros from a digit list: + +```ts +import { $, DigitList } from "hkt-toolbelt"; + +type Result = $; // ["5", "0", "2"] +``` + +In this example, `Result` is a type that represents the digit list ["5", "0", "2"], which is the result of trimming the leading zeros from the digit list ["0", "5", "0", "2"]. + + + +# Module: Function + +The `Function` module contains various utilities for working with function +types. Function types are used in various contexts, such as representing +higher-order functions. + + +```ts +import { $, Function } from 'hkt-toolbelt' + +type Result = $<$ string>, 42> // string +``` + + +| Utility name | Description | +| -- | -- | + | [Constant](#utility-functionconstant) | `Constant` is a type-level function that constructs a type-level function which always returns the given value, regardless of input. | + | [Function](#utility-functionfunction) | `Function` is the top type (supertype) of all function types in TypeScript. | + | [Identity](#utility-functionidentity) | `Identity` is a type-level utility that returns its input type unchanged. | + | [ReturnType](#utility-functionreturntype) | `ReturnType` extracts the return type of a function type. | + + +## Utility: Function.Constant + +`Constant` is a type-level function that constructs a type-level function +which always returns the given value, regardless of input. + +| Argument name | Type | Description | +| -- | -- | -- | +| T | | The constant value to return. | + +@returns The configured constant value T. + + + +```ts +import { $, Function } from 'hkt-toolbelt' + +// Returns 'foo' regardless of input +type C = $<$, 0> // 'foo' +type D = $<$, 'bar'> // 'foo' +``` + + + +## Utility: Function.Function + +`Function` is the top type (supertype) of all function types in TypeScript. + +It specifies `never[]` as the parameter types because: + +1. Parameters are contravariant, so for a function A to be assignable to B, + the parameters of B must be assignable to the parameters of A. + +2. We want every other function to be assignable to `Function`, i.e. be a + subtype of Function. + +3. `never` is the only type assignable to all other types. It is the bottom + type (subtype) of all types. + +So by using `never[]` parameters, `Function` becomes assignable from any +other function type, making it the top type. + + + + +## Utility: Function.Identity + +`Identity` is a type-level utility that returns its input type unchanged. + +It acts as the "identity" function at the type level. + +| Argument name | Type | Description | +| -- | -- | -- | +| T | | The input type to return unchanged | + +@returns The input value x, unchanged + + +```ts +import { $, Function } from 'hkt-toolbelt' + +// Returns 'foo' +type R = $ +``` + +The `Identity` utility is often useful for disabling side effects of +other types within a pipeline. + + + +## Utility: Function.ReturnType + +`ReturnType` extracts the return type of a function type. + +| Argument name | Type | Description | +| -- | -- | -- | +| x | | A function type | + + +```ts +import { $ } from 'hkt-toolbelt' + +type Fn = (a: number) => string + +type R = $ // string +``` + +This utility can be useful for extracting the return type of a function without +having to call it. + + + +# Module: Integer + +The `Integer` module contains various utilities for working with integer +types, i.e. signed and unsigned integers. + + +```ts +import { $, Integer } from 'hkt-toolbelt' + +type Result = $<$, -2> // -1 +``` + + +| Utility name | Description | +| -- | -- | + | [Add](#utility-integeradd) | `Add` is a type-level function that takes in two integers `A` and `B`, and returns the sum of the two integers. | + | [Compare](#utility-integercompare) | `Compare` is a type-level function that takes in two integer types `A` and `B`, and returns the comparison result as an integer type. The result will be 1 if `A` is greater than `B`, 0 if `A` is equal to `B`, and -1 if `A` is less than `B`. | + | [Decrement](#utility-integerdecrement) | `Decrement` is a type-level function that decrements an integer type. It returns the decremented integer. | + | [DivideBy](#utility-integerdivideby) | `DivideBy` is a type-level function that takes in two integer types, `A` and `B`, and returns the result of dividing `B` by `A`. | + | [Divide](#utility-integerdivide) | `Divide` is a type-level function that takes in two integers and performs a division operation. It returns the result of the division operation. | + | [Increment](#utility-integerincrement) | `Increment` is a type-level function that increments an integer type. It returns the incremented integer. | + | [IsEven](#utility-integeriseven) | `IsEven` is a type-level function that takes in an integer type, `A`, and returns a boolean indicating whether `A` is an even number | + | [IsGreaterThanOrEqual](#utility-integerisgreaterthanorequal) | `IsGreaterThanOrEqual` is a type-level function that takes in two integer types, `A` and `B`, and returns a boolean indicating whether `B` is greater than or equal to `A`. | + | [IsGreaterThan](#utility-integerisgreaterthan) | `IsGreaterThan` is a type-level function that takes in two integer types, `A` and `B`, and returns a boolean indicating whether `B` is greater than `A`. | + | [IsLessThanOrEqual](#utility-integerislessthanorequal) | `IsLessThanOrEqual` is a type-level function that takes in two integer types, `A` and `B`, and returns a boolean indicating whether `B` is less than or equal to `A`. | + | [IsLessThan](#utility-integerislessthan) | `IsLessThan` is a type-level function that takes in two integer types, `A` and `B`, and returns a boolean indicating whether `B` is less than `A`. | + | [IsOdd](#utility-integerisodd) | `IsOdd` is a type-level function that takes in an integer type, `A`, and returns a boolean indicating whether `A` is an odd number | + | [ModuloBy](#utility-integermoduloby) | `ModuloBy` is a type-level function that takes in two integer types, `A` and `B`, and returns the floored modulo of `B` divided by `A`. | + | [Modulo](#utility-integermodulo) | `Modulo` is a type-level function that takes in two natural number types, `A` and `B`, and returns the floored modulo of `A` divided by `B`. | + | [Multiply](#utility-integermultiply) | `Multiply` is a type-level function that multiplies an integer by another integer. It returns the result of the multiplication operation. | + | [RemainderBy](#utility-integerremainderby) | `RemainderBy` is a type-level function that takes in two integer types, `A` and `B`, and returns the remainder of `B` divided by `A`. | + | [Remainder](#utility-integerremainder) | `Remainder` is a type-level function that takes in two integer types, `A` and `B`, and returns the remainder of `A` divided by `B`. | + | [SubtractBy](#utility-integersubtractby) | `SubtractBy` is a type-level function that takes in two integer types, `A` and `B`, and returns the result of subtracting `A` from `B`. | + | [Subtract](#utility-integersubtract) | `Subtract` is a type-level function that subtracts one integer from another. It returns the result of the subtraction. | + + +## Utility: Integer.Add + +`Add` is a type-level function that takes in two integers `A` and `B`, +and returns the sum of the two integers. + +| Argument name | Type | Description | +| -- | -- | -- | +| A | `Number.Number` | An integer. | +| B | `Number.Number` | An integer. | + +If one or more of the inputs is not an integer, an error is emitted. + + +For example, we can use `Add` to add the two integers -123 and 456: + +We apply `Add` to -123 and 456 respectively using +the `$` type-level applicator: + +```ts +import { $, Integer } from "hkt-toolbelt" + +type Result = $<$, 456> // 333 +``` + + +If one of the inputs is not a natural number, `never` is returned. + +```ts +import { Integer } from "hkt-toolbelt"; + +type IsNever = $; // never +``` + + + +## Utility: Integer.Compare + +`Compare` is a type-level function that takes in +two integer types `A` and `B`, and returns the comparison result as an integer type. +The result will be 1 if `A` is greater than `B`, +0 if `A` is equal to `B`, and -1 if `A` is less than `B`. + +| Argument name | Type | Description | +| -- | -- | -- | +| A | `Number.Number` | An integer type. | +| B | `Number.Number` | An integer type. | + + +For example, we can use `Compare` to compare two integers. + +```ts +import { $, Integer } from "hkt-toolbelt"; + +type Result1 = $<$, -321>; // 1 +type Result2 = $<$, 321>; // -1 +``` + + + +## Utility: Integer.Decrement + +`Decrement` is a type-level function that decrements an integer type. +It returns the decremented integer. + +| Argument name | Type | Description | +| -- | -- | -- | +| A | `Number.Number` | - The integer to decrement. | + +If the input is not an integer, `never` is returned. + + +For example, we can use `Decrement` to decrement an integer: + +```ts +import { $, Integer, Type } from "hkt-toolbelt"; + +type Result = $; // -1 +``` + + +If the input is not an integer, `never` is returned. + +```ts +import { Integer } from "hkt-toolbelt"; + +type IsNever = $; // never +``` + + + +## Utility: Integer.DivideBy + +`DivideBy` is a type-level function that takes in two integer types, +`A` and `B`, and returns the result of dividing `B` by `A`. + +| Argument name | Type | Description | +| -- | -- | -- | +| A | `Number.Number` | An integer to divide by. | +| B | `Number.Number` | An integer to be divided. | + +The parameters are reversed from `Divide`. This is useful for partial +application, i.e. to test divisibility. + + +For example, we can apply `DivideBy` to the type argument 3 using the `$` type-level applicator, +and evaluate the results of dividing multiple integers by 3. + +```ts +import { $, Integer } from "hkt-toolbelt"; + +type DivideByThree = $; + +type Result1 = $; // 1 +type Result2 = $; // -1 +``` + + +If one of the inputs is not an integer, `never` is returned. + +```ts +import { $, Integer } from "hkt-toolbelt"; + +type IsNever = $; // never +``` + + + +## Utility: Integer.Divide + +`Divide` is a type-level function that takes in two integers and performs a division operation. +It returns the result of the division operation. + +| Argument name | Type | Description | +| -- | -- | -- | +| A | `Number.Number` | An integer to divide. | +| B | `Number.Number` | An integer to divide by. | + +If `A` is not a multiple of `B`, the quotient is returned and the remainder is thrown away. +The quotient is truncated towards zero. That is, `-1/2` is evaluated to be 0, not -1. + +If either input is not a integer, `never` is returned. + + +For example, we can use `Divide` to create a division operation that divides 10 by -2: + +```ts +import { $, Integer } from "hkt-toolbelt"; + +type Result = $<$, -2>; // -5 +``` + + +If `A` is not a multiple of `B`, the result is truncated towards zero, +and only the quotient is returned. + +```ts +import { $, Integer } from "hkt-toolbelt"; + +type Result = $<$, 99>; // -1 +``` + + +If one of the inputs is not a integer, `never` is returned. + +```ts +import { $, Integer } from "hkt-toolbelt"; + +type IsNever = $; // never +``` + + + +## Utility: Integer.Increment + +`Increment` is a type-level function that increments an integer type. +It returns the incremented integer. + +| Argument name | Type | Description | +| -- | -- | -- | +| A | `Number.Number` | - The integer to increment. | + +If the input is not an integer, `never` is returned. + + +For example, we can use `Increment` to increment an integer: + +```ts +import { $, Integer, Type } from "hkt-toolbelt"; + +type Result = $; // -9 +``` + + +If the input is not an integer, `never` is returned. + +```ts +import { Integer } from "hkt-toolbelt"; + +type IsNever = $; // never +``` + + + +## Utility: Integer.IsEven + +`IsEven` is a type-level function that takes in an integer type, +`A`, and returns a boolean indicating whether `A` is an even number + +@template {Number.Number} A - An integer type. +@returns {boolean} + + + +## Utility: Integer.IsGreaterThanOrEqual + +`IsGreaterThanOrEqual` is a type-level function that takes in two integer +types, `A` and `B`, and returns a boolean indicating whether `B` is greater +than or equal to `A`. + +| Argument name | Type | Description | +| -- | -- | -- | +| A | `Number.Number` | An integer to compare against. | +| B | `Number.Number` | An integer to evaluate. | + +The parameters are ordered such that `IsGreaterThanOrEqual` can be partially applied +in a coherent manner. That is, we can apply `IsGreaterThanOrEqual` to `3`, and have a +function `IsGreaterThanOrEqualToThree`. + + +For example, we can use `IsGreaterThanOrEqual` to determine whether an integer is +less than or equal to another integer. In this example, `-3` and `-2` are passed as +type arguments to the type-level function: + +We apply `IsGreaterThanOrEqual` to `-3`, and then to `-2` respectively using the `$` +type-level applicator: + +```ts +import { $, Integer } from "hkt-toolbelt"; + +type Result = $<$, -2>; // true +``` + + +If we apply `IsGreaterThanOrEqual` to `-3` and `-3`, we should expect to get `true`. + +```ts +import { $, Integer } from "hkt-toolbelt"; + +type Result = $<$, -3>; // true +``` + + +If we apply `IsGreaterThanOrEqual` to `-3` and `-4`, we should also expect to get +`false`. + +```ts +import { $, Integer } from "hkt-toolbelt"; + +type Result = $<$, -4>; // false +``` + + + +## Utility: Integer.IsGreaterThan + +`IsGreaterThan` is a type-level function that takes in two integer +types, `A` and `B`, and returns a boolean indicating whether `B` is greater +than `A`. + +| Argument name | Type | Description | +| -- | -- | -- | +| A | `Number.Number` | An integer to compare against. | +| B | `Number.Number` | An integer to evaluate. | + +The parameters are ordered such that `IsGreaterThan` can be partially applied +in a coherent manner. That is, we can apply `IsGreaterThan` to `3`, and have a +function `IsGreaterThanThree`. + + +For example, we can use `IsGreaterThan` to determine whether an integer is +greater than another integer. In this example, `-2` and `-3` are passed as +type arguments to the type-level function: + +We apply `IsGreaterThan` to `-3`, and then to `-2` respectively using the `$` +type-level applicator: + +```ts +import { $, Integer } from "hkt-toolbelt"; + +type Result = $<$, -2>; // true +``` + + +If we apply `IsGreaterThan` to `-3` and `-3`, we should expect to get `false`. + +```ts +import { $, Integer } from "hkt-toolbelt"; + +type Result = $<$, -3>; // false +``` + + +If we apply `IsGreaterThan` to `-3` and `-4`, we should expect to get `false`. + +```ts +import { $, Integer } from "hkt-toolbelt"; + +type Result = $<$, -4>; // false +``` + + + +## Utility: Integer.IsLessThanOrEqual + +`IsLessThanOrEqual` is a type-level function that takes in two integer +types, `A` and `B`, and returns a boolean indicating whether `B` is less +than or equal to `A`. + +| Argument name | Type | Description | +| -- | -- | -- | +| A | `Number.Number` | An integer to compare against. | +| B | `Number.Number` | An integer to evaluate. | + +The parameters are ordered such that `IsLessThanOrEqual` can be partially applied +in a coherent manner. That is, we can apply `IsLessThanOrEqual` to `3`, and have a +function `IsLessThanOrEqualToThree`. + + +For example, we can use `IsLessThanOrEqual` to determine whether an integer is +less than or equal to another integer. In this example, `-3` and `-4` are passed as +type arguments to the type-level function: + +We apply `IsLessThanOrEqual` to `-3`, and then to `-4` respectively using the `$` +type-level applicator: + +```ts +import { $, Integer } from "hkt-toolbelt"; + +type Result = $<$, -4>; // true +``` + + +If we apply `IsLessThanOrEqual` to `-3` and `-3`, we should expect to get `true`. + +```ts +import { $, Integer } from "hkt-toolbelt"; + +type Result = $<$, -3>; // true +``` + + +If we apply `IsLessThanOrEqual` to `-3` and `4`, we should also expect to get +`false`. + +```ts +import { $, Integer } from "hkt-toolbelt"; + +type Result = $<$, 4>; // false +``` + + + +## Utility: Integer.IsLessThan + +`IsLessThan` is a type-level function that takes in two integer +types, `A` and `B`, and returns a boolean indicating whether `B` is less +than `A`. + +| Argument name | Type | Description | +| -- | -- | -- | +| A | `Number.Number` | An integer to compare against. | +| B | `Number.Number` | An integer to compare. | + +The parameters are ordered such that `IsLessThan` can be partially applied +in a coherent manner. That is, we can apply `IsLessThan` to `3`, and have a +function `IsLessThanThree`. + + +For example, we can use `IsLessThan` to determine whether an integer is +less than another integer. In this example, `-4` and `-3` are passed as +type arguments to the type-level function: + +We apply `IsLessThan` to `-3`, and then to `-4` respectively using the `$` +type-level applicator: + +```ts +import { $, Integer } from "hkt-toolbelt"; + +type Result = $<$, -4>; // true +``` + + +If we apply `IsLessThan` to `-3` and `-3`, we should expect to get `false`. + +```ts +import { $, Integer } from "hkt-toolbelt"; + +type Result = $<$, -3>; // false +``` + + +If we apply `IsLessThan` to `-3` and `4`, we should expect to get `false`. + +```ts +import { $, Integer } from "hkt-toolbelt"; + +type Result = $<$, 4>; // false +``` + + + +## Utility: Integer.IsOdd + +`IsOdd` is a type-level function that takes in an integer type, +`A`, and returns a boolean indicating whether `A` is an odd number + +@template {Number.Number} A - An integer type. +@returns {boolean} + + + +## Utility: Integer.ModuloBy + +`ModuloBy` is a type-level function that takes in two integer types, +`A` and `B`, and returns the floored modulo of `B` divided by `A`. + +| Argument name | Type | Description | +| -- | -- | -- | +| A | `Number.Number` | An integer to divide by to calculate the modulo. | +| B | `Number.Number` | An integer type to be divided numerator. | + +The parameters are reversed from `Modulo`. This is useful for partial +application, i.e. to test divisibility. + + +For example, we can use `ModuloBy` to determine the remainder +of an integer divided by another integer. In this example, `3` and `4`, `-4` are +passed as type arguments to the type-level function: + +```ts +import { $, Integer } from "hkt-toolbelt"; + +type ModuloByThree = $; + +type Result = $; // 1 +type Result = $; // 3 +``` + + + +## Utility: Integer.Modulo + +`Modulo` is a type-level function that takes in two natural number types, +`A` and `B`, and returns the floored modulo of `A` divided by `B`. + +Modulo `k` is defined as `k := n - d * q` where `q` is the integer such that +`k` has the same sign as the divisor `d` while being as close to 0 as possible. + +Modulo `k` is also equivalent to `k := ((n % d) + d) % d`, +where `%` is the remainder operator in javascript. + +The sign of output `k` is always the same as the divisor `B`, +and the value of `k` is always within the range `-B < k < B`. + +| Argument name | Type | Description | +| -- | -- | -- | +| A | `Number.Number` | An integer to divide. | +| B | `Number.Number` | An integer to divide by. | + + +For example, we can use `Modulo` to determine the modulo of an integer +divided by another integer. In this example, `10`, `-10` and `3`, `-3` are +passed as type arguments to the type-level function: + +We apply `Modulo` to `10` and `-10`, and then to `3` and `-3` respectively using the `$` +type-level applicator: + +```ts +import { $, Integer } from "hkt-toolbelt"; + +type Result1 = $<$, 3>; // 1 +type Result2 = $<$, -3>; // -2 +type Result3 = $<$, 3>; // 2 +type Result4 = $<$, -3>; // -1 +``` + + +Here we calculate the modulo of `123` or `-123` divided by `17` or `-17`: + +```ts +import { $, Integer } from "hkt-toolbelt"; + +type Result1 = $<$, 17>; // 4 +type Result2 = $<$, -17>; // -13 +type Result3 = $<$, 17>; // 13 +type Result4 = $<$, -17>; // -4 +``` + + + +## Utility: Integer.Multiply + +`Multiply` is a type-level function that multiplies an integer by another integer. +It returns the result of the multiplication operation. + +| Argument name | Type | Description | +| -- | -- | -- | +| A | `Number.Number` | - An integer. | +| B | `Number.Number` | - An integer. | + +If one or more of the inputs is not an integer, an error is emitted. + + +For example, we can use `Multiply` to multiply an integer 456 by another integer -123: + +```ts +import { $, NaturalNumber } from "hkt-toolbelt"; + +type Is504 = $<$, 456>; // -56088 +type Is504Str = $<$, '456'>; // -56088 +``` + + +If one of the inputs is zero, the result will be zero. + +```ts +import { NaturalNumber } from "hkt-toolbelt"; + +type IsZero = $<$, 42>; // 0 +``` + + +If one of the inputs is not an integer, `never` is returned. + +```ts +import { NaturalNumber } from "hkt-toolbelt"; + +type IsNever = $; // never +``` + + + +## Utility: Integer.RemainderBy + +`RemainderBy` is a type-level function that takes in two integer types, +`A` and `B`, and returns the remainder of `B` divided by `A`. + +| Argument name | Type | Description | +| -- | -- | -- | +| A | `Number.Number` | An integer to divide by to calculate the remainder. | +| B | `Number.Number` | The numerator. | + +The parameters are reversed from `Remainder`. This is useful for partial +application, i.e. to test divisibility. + + +For example, we can use `RemainderBy` to determine the remainder +of an integer divided by another integer. In this example, `3` and `4`, `-4` are +passed as type arguments to the type-level function: + +```ts +import { $, Integer } from "hkt-toolbelt"; + +type RemainderByThree = $; + +type Result1 = $; // 4 % 3 = 1 +type Result2 = $; // -4 % 3 = -1 +``` + + + +## Utility: Integer.Remainder + +`Remainder` is a type-level function that takes in two integer types, +`A` and `B`, and returns the remainder of `A` divided by `B`. + +| Argument name | Type | Description | +| -- | -- | -- | +| A | `Number.Number` | An integer to divide. | +| B | `Number.Number` | An integer to divide by. | + + +For example, we can use `Remainder` to determine the remainder of an integer +divided by another integer. In this example, all four combinations of +`+/-3`, `+/-2` are passed as type arguments to the type-level function: + +We apply `Remainder` to `+/-3`, and then to `+/-2` respectively using the `$` +type-level applicator: + +```ts +import { $, Integer } from "hkt-toolbelt"; + +type Result1 = $<$, 2>; // 1 +type Result2 = $<$, -2>; // 1 +type Result3 = $<$, -2>; // -1 +type Result4 = $<$, 2>; // -1 +``` + + +Here we calculate the remainder of `10` and `-10` divided by `3` and `-3`: + +```ts +import { $, Integer } from "hkt-toolbelt"; + +type Result1 = $<$, 3>; // 1 +type Result2 = $<$, -3>; // 1 +type Result3 = $<$, -3>; // -1 +type Result4 = $<$, 3>; // -1 +``` + + + +## Utility: Integer.SubtractBy + +`SubtractBy` is a type-level function that takes in two integer types, +`A` and `B`, and returns the result of subtracting `A` from `B`. + +| Argument name | Type | Description | +| -- | -- | -- | +| A | `Number.Number` | An integer to subtract by. | +| B | `Number.Number` | An integer to be subtracted from. | + +The parameters are reversed from `Subtract`. This is useful for partial +application, i.e. to test divisibility. + + +For example, we can apply `SubtractBy` to the type argument 3 using the `$` type-level applicator, +and evaluate the results of subtracting multiple integers by 3. + +```ts +import { $, Integer } from "hkt-toolbelt"; + +type SubtractByThree = $; + +type Result1 = $; // 1 +type Result2 = $; // -7 +``` + + +If one of the inputs is not an integer, `never` is returned. + +```ts +import { $, Integer } from "hkt-toolbelt"; + +type IsNever = $; // never +``` + + + +## Utility: Integer.Subtract + +`Subtract` is a type-level function that subtracts one integer from +another. It returns the result of the subtraction. + +| Argument name | Type | Description | +| -- | -- | -- | +| A | `Number.Number` | An integer to subtract. | +| B | `Number.Number` | An integer to subtract by. | + + +For example, we can use `Subtract` to subtract one integer from another: + +```ts +import { $, Integer } from "hkt-toolbelt"; + +type Result = $<$, 25>; // -75 +``` + + +If one of the inputs is not a integer, `never` is returned. + +```ts +import { $, Integer } from "hkt-toolbelt"; + +type IsNever = $; // never +``` + + + +# Module: Kind + +The `Kind` module contains various utilities for working with higher-kinded +types. Higher-kinded types are used in various contexts, such as representing +and manipulating higher-order functions, and composing types. + + +```ts +import { $, Kind } from 'hkt-toolbelt' + +type Result = $<$, Function.Identity> // [1, 2, 3] +``` + + +| Utility name | Description | +| -- | -- | + | [ApplyN](#utility-kindapplyn) | `ApplyN` is a type-level function that applies a kind to a type. | + | [Apply](#utility-kindapply) | `Apply` is a type-level function that applies a kind to a type. | + | [Arity](#utility-kindarity) | `Arity` is a type-level function that takes in a curried type-level function, and returns the total number of arguments it needs in order to be fully applied. | + | [ComposablePair](#utility-kindcomposablepair) | `ComposablePair` checks if two kinds can be composed together. | + | [Composable](#utility-kindcomposable) | `Composable` checks whether a sequence of kinds can be composed without errors. | + | [Compose](#utility-kindcompose) | `Compose` is a type-level function that allows users to compose multiple type-level functions together. It takes in a list of functions and a type argument as input, composes the functions in its input list from right to left, and returns a higher-kinded-type function that takes in a type and returns the result of the composition. | + | [Curry](#utility-kindcurry) | `Curry` is a combinator that takes in a positive natural number `N` and a type-level function `K`, which expects a tuple of length `N`, and returns a curried type-level function with `N` arity. | + | [InputOf](#utility-kindinputof) | Represents a type-level utility to deduce the input type of a provided kind. | + | [Juxt](#utility-kindjuxt) | `Juxt` is a type-level function that applies a tuple of kinds to a type. | + | [OutputOf](#utility-kindoutputof) | Represents a type-level utility to deduce the output type of a provided kind. | + | [Parameters](#utility-kindparameters) | `Parameters` is a type-level function that takes in a curried n-ary type-level function, and returns an ordered of the types of the n arguments that the input function is expecting. | + | [PipeWeak](#utility-kindpipeweak) | `PipeWeak` is a type-level function that takes a tuple of type-level functions and composes them from left to right, such that the output of the first function is the input of the second function, and so on. | + | [Pipe](#utility-kindpipe) | `Pipe` is a type-level function that allows users to compose multiple type-level functions together. It takes in a list of functions and a type argument as input, composes the functions in its input list from left to right, and and applies the resulting type-level function to the second input type. | + | [Reify](#utility-kindreify) | Represents a type-level utility to reify a kind into a function signature. The `Reify` interface is a more structured way to use the reification process, and is built upon the `_$reify` type. | + | [Unapply](#utility-kindunapply) | `Unapply` is a type-level function that takes in a) a type-level function that has been partially or fully applied with an argument, b) the original type-level function that was invoked to derive the first input type, and then extracts and returns the applied argument from closure. | + | [Uncurry](#utility-kinduncurry) | `Uncurry` is a type-level function that takes in a type-level function and a list of arguments, and applies the type-level function to the list of arguments. | + + +## Utility: Kind.ApplyN + +`ApplyN` is a type-level function that applies a kind to a type. + +It takes a list of arguments X and kind K, and applies +K to X using the `$N` operator. + +@see {@link Kind.Uncurry} + +`ApplyN` is `Kind.Uncurry` with the argument positions reversed. +Here, we first take in the values, and then a kind to apply to those values. + +This makes `ApplyN` particularly useful for more complicated chains +of type-level logic. + +| Argument name | Type | Description | +| -- | -- | -- | +| X | | The list of arguments to apply the kind to | +| K | | The kind to apply | + +@returns The result of applying K to X + + + +## Utility: Kind.Apply + +`Apply` is a type-level function that applies a kind to a type. + +It takes a value X and kind K, casts X to the input type of K, and applies +K to the casted X using the `$` operator. + +@see {@link $} +Notably, the argument positions are reversed compared to `\$`. +Here, we first take in a value, and then a kind to apply to that value. + +| Argument name | Type | Description | +| -- | -- | -- | +| X | | The value of type X to apply the kind to | +| K | | The kind to apply | + +@returns The result of applying K to x + + + +For a simple example, we can apply `Identity` to the type 42: + +```ts +import { $, Kind, Function } from 'hkt-toolbelt' + +type X = $<$, Function.Identity> // 42 +``` + + + +`Apply` is particularly useful for more complicated chains of type-level +logic. For example, we can map over a list of kinds and apply all of them +to an input type: + +```ts +import { $, Kind, List, String } from 'hkt-toolbelt' + +type X = $< + $>, + [$, $, String.ToUpper] +> +// ['fooqux', 'quxbar', 'QUX'] +``` + +In the above example, we map over a list of kinds, and apply each of them +to the input type `'qux'`. The result is a list of types, each of which +is the result of applying the corresponding kind to `'qux'`. + + + +## Utility: Kind.Arity + +`Arity` is a type-level function that takes in a curried type-level function, +and returns the total number of arguments it needs in order to be fully applied. + +| Argument name | Type | Description | +| -- | -- | -- | +| K | `Kind.Kind` | A type-level function whose arity will be returned. | + +If `K` is a fully-applied `Kind`, 0 will be returned. +If `K` is not a `Kind`, an error will be emitted. + + +```ts +type ReduceArity = $ // 3 +type PartialApply1 = $> // 2 +type PartialApply2 = $, never>> // 1 +type FullApply = $, never>, never>> // 0 +``` + + + +## Utility: Kind.ComposablePair + +`ComposablePair` checks if two kinds can be composed together. + +It takes a pair of kinds [A, B] and returns true if B's output type is a +subtype of A's input type. This means that B can be piped into A. + +Equivalently, A can be composed with B. Regarding terminology, f(g(x)) is f +composed with g, and we say that 'g is piped into f'. In other words, +composition is a right-to-left description. + +| Argument name | Type | Description | +| -- | -- | -- | +| K | | A tuple containing two kinds to check | + +@returns Whether the kinds are composable + + +```ts +// Returns true - length results in a number, which can be incremented. +$ + +// Returns false - reverse results in a list, which cannot be upper-cased. +$ +``` + + + +## Utility: Kind.Composable + +`Composable` checks whether a sequence of kinds can be composed without +errors. + +It should be invoked via `$` by passing a tuple of kinds: + +```ts +$ +``` + +This will evaluate to a boolean literal type indicating whether the kinds in the tuple are composable: + +- `true` if each adjacent pair is composable. +- `false` otherwise. + +Two kinds `X` and `Y` are composable if `X`'s output type is a subtype of `Y`'s input type. + +| Argument name | Type | Description | +| -- | -- | -- | +| K | | The tuple of kinds to check | + + + +```ts +// true - number => number => string is a valid chain +$ + +// false - the chain breaks +$ +``` + +@see {@link _$composable} +`Composable` is the public interface for `_$composable` which performs the +checks. + + + +## Utility: Kind.Compose + +`Compose` is a type-level function that allows users to compose +multiple type-level functions together. It takes in a list of functions and a type argument as input, +composes the functions in its input list from right to left, +and returns a higher-kinded-type function that takes in a type and returns the result of the composition. + +| Argument name | Type | Description | +| -- | -- | -- | +| FX | `Kind.Kind[]` | a tuple of type-level functions | +| X | | a type to which a `Kind` can be applied. | + +@see {@link Kind.Pipe} +`Kind.Pipe` provides the same functionality as `Compose` but evaluates the list of functions in reverse order. + +@see {@link $$} +While `$$` immediately applies a composed function to an input, +`Compose` can also be passed into other higher-order type-level functions without being invoked. + +## Errors + +`Compose` ensures that the tuple of kinds is composable by enforcing that +the Nth type-level function's output is a subtype of the (N + 1)th input. +If this is not the case, `Compose` will return the `never` type. + +@see {@link Kind.InputOf} {@link Kind.OutputOf} +If you receive a `never` type, it can be helpful to use the `Kind.InputOf` +and `Kind.OutputOf` type-level functions to inspect the input and output +types of the type-level functions that you are composing together. + + + +## Utility: Kind.Curry + +`Curry` is a combinator that takes in a positive natural number `N` and +a type-level function `K`, which expects a tuple of length `N`, and returns +a curried type-level function with `N` arity. + +The resultant type-level function expects `N` arguments, applied via nested +`$` applications. Alternatively, `$N` can be used to apply the arguments +as a tuple, i.e. through an 'uncurried' application. + +Internally, `Curry` keeps an internal tuple that it appends to as each +argument is applied. Once the tuple has `N` elements, it applies the +type-level function `K` to the tuple. + +| Argument name | Type | Description | +| -- | -- | -- | +| N | `Number.Number` | The number of arguments to expect. | +| K | `Kind.Kind` | The type-level function to curry. | + +See `Combinator.Collate` for a similar combinator. + + +```ts +import { $, Kind, Type } from "ts-toolbelt" + +type Result = $N + + + +## Utility: Kind.InputOf + +Represents a type-level utility to deduce the input type of a provided kind. + +| Argument name | Type | Description | +| -- | -- | -- | +| F | | The kind whose input type needs to be inferred. | + +@returns The inferred input type of the provided kind. If the kind doesn't +have a deducible input type, it will return `unknown`. + + +// Given a kind that represents the addition of a natural number with 2: +type Add2 = $; +// You can use Kind.InputOf to deduce the input type of this kind: +type InputType = $; // This will be inferred as Number.Number + + +// For more complex kinds: +type ReduceAdd = $; +type InputType2 = $; // This will be inferred as unknown + +type ReduceAdd0 = $; +type InputType3 = $; // This will be inferred as unknown[] + + + +## Utility: Kind.Juxt + +`Juxt` is a type-level function that applies a tuple of kinds to a type. + +This is useful for implementing point-free style type-level functions. + +| Argument name | Type | Description | +| -- | -- | -- | +| FX | | A tuple of kinds to apply. | +| X | | The input type to apply the kinds to. | + +@returns A tuple of the results of applying each kind in the tuple to `X`. + + + +In the below example, we apply `Kind.Juxt` to a tuple of two kinds, +List.Length and List.Reverse. On the successive line, we apply the kinds to +the input type `[1, 2, 3]`. The result is a tuple of two types, the first +being the length of the input list `[1, 2, 3]` (3), and the second being the +reversed list `[3, 2, 1]`. + +```ts +import { $, Kind, List } from "hkt-toolbelt"; + +type MyJuxt = $; + +type Result = MyJuxt<[1, 2, 3]>; // [3, [3, 2, 1]] +``` + + + +## Utility: Kind.OutputOf + +Represents a type-level utility to deduce the output type of a provided kind. + +| Argument name | Type | Description | +| -- | -- | -- | +| F | | The kind whose output type needs to be inferred. | + +@returns The inferred output type of the provided kind. If the kind doesn't have a deducible output type, it will return `unknown`. + + +// Using the `String.ToUpper` kind which converts a string to uppercase: +// You can use Kind.OutputOf to deduce the output type of this kind: +type OutputType = $; // This will be inferred as string + + + +## Utility: Kind.Parameters + +`Parameters` is a type-level function that takes in a curried n-ary type-level function, +and returns an ordered of the types of the n arguments that the input function is expecting. + +| Argument name | Type | Description | +| -- | -- | -- | +| K | `Kind.Kind` | A type-level function whose parameters will be returned. | + +`K` can be applied successively to a series of arguments that extend each element of the +list returned by `Parameters` by using the @see {@link `$`} operator. + +`K` can also be applied to a list of arguments that extends the list returend by `Parameters` +by using the @see {@link `$N`} operator. + +If `K` is a fully-applied `Kind`, an empty list will be returned. +If `K` is not a `Kind`, an error will be emitted. + + +type ReduceParams = $ // [Kind.Kind<(x: never) => Kind.Kind>, unknown, List.List] +type PartialApply1 = $> // [unknown, List.List] +type PartialApply2 = $, never>> // [List.List] +type FullApply = $, never>, never>> // [] + + + +## Utility: Kind.PipeWeak + +`PipeWeak` is a type-level function that takes a tuple of type-level +functions and composes them from left to right, such that the output of the +first function is the input of the second function, and so on. + +This is a weaker version of `Pipe` that does not enforce subtype +constraints between the input and output of each function. + +The type constraint associated with the overall input, and the constraint +enforcing a tuple of kinds are both still enforced. + +This is useful for pipes which are too complicated for the inputs and outputs +to be correctly inferred. + +| Argument name | Type | Description | +| -- | -- | -- | +| FX | | A tuple of type-level functions that will be piped together. | +| X | | The type that the type-level functions will be applied to. | + + + +```ts +import { $, Kind, String } from "hkt-toolbelt"; + +type MyFunc = $, + $, +]> + +type Result = $ // "bazfoobar" +``` + + + +## Utility: Kind.Pipe + +`Pipe` is a type-level function that allows users to compose +multiple type-level functions together. It takes in a list of functions and a type argument as input, +composes the functions in its input list from left to right, and +and applies the resulting type-level function to the second input type. + +| Argument name | Type | Description | +| -- | -- | -- | +| FX | `Kind.Kind[]` | a tuple of type-level functions | +| X | | a type to which a `Kind` can be applied | + +@see {@link Kind.Compose} +The functionality of `Pipe` is identical to `Kind.Compose` +except for the order of evaluation being reversed, which has the advantage of improved readability. + +@see {@link $$} +In short, `Pipe` is the partially applicable formulation of `$$`. +While `$$` immediately applies a composed function to an input, +`Pipe` can also be passed into other higher-order type-level functions without being invoked. + +## Errors + +`Pipe` ensures that the tuple of kinds is composable by enforcing that +Nth type-level function's output is a subtype of the (N + 1)th input. +If this is not the case, `Pipe` will return the `never` type. + +@see {@link Kind.InputOf} {@link Kind.OutputOf} +If you receive a `never` type, it can be helpful to use the `Kind.InputOf` +and `Kind.OutputOf` type-level functions to inspect the input and output +types of the type-level functions that you are piping together. + + + +## Utility: Kind.Reify + +Represents a type-level utility to reify a kind into a function signature. +The `Reify` interface is a more structured way to use the reification process, and is built upon the `_$reify` type. + +| Argument name | Type | Description | +| -- | -- | -- | +| F | | The kind to be reified. | + +@returns A function signature derived from the provided kind. + + +// Using the `String.ToUpper` kind, you can use Reify to get a function-like signature: +declare const toUpper: $; +// This function can be used as a 'reified kind', with type inference. +const x = toUpper('hello'); // 'HELLO' + + + +## Utility: Kind.Unapply + +`Unapply` is a type-level function that takes in +a) a type-level function that has been partially or fully applied with an argument, +b) the original type-level function that was invoked to derive the first input type, +and then extracts and returns the applied argument from closure. + +| Argument name | Type | Description | +| -- | -- | -- | +| K | `Kind.Kind` | The target type-level function to unapply. | +| F | `Kind.Kind` | The type-level function that was applied to an argument to derive `K` | + +Note that `_$unapply` infers the most specific type for the closure argument, +whereas `Kind._$inputOf` returns the widest category of arguments accepted by the input function. + + +For example, we can use `Unapply` to determine what argument was passed into an applied type-level function. +In this example, we partially apply `Unapply` to `NaturalNumber.Add`, which results in a +type-level function that returns the argument passed into `NaturalNumber.Add` to derive its input, +if its input is the result of applying that function. + +We then apply this partially applied function to `Add2` using the `$` type-levl applicator: + +```ts +import { $, Kind, NaturalNumber } from "hkt-toolbelt"; + +type Add2 = $ +type Is2 = $<$, Add2> // 2 +``` + + + +## Utility: Kind.Uncurry + +`Uncurry` is a type-level function that takes in a type-level function and +a list of arguments, and applies the type-level function to the list of +arguments. + +This is syntactic sugar for nested `$` applications. See `$N`, which is the +operator shorthand for this function. + +| Argument name | Type | Description | +| -- | -- | -- | +| K | `Kind.Kind` | The type-level function to apply. | +| X | `List.List` | The list of arguments to apply the type-level function to. | + +This is useful for applying a type-level function that takes many arguments, +such as conditionals. + +Additionally, this can be used in conjunction with `Curry` to "lift" +arguments out of function composition. + + + +# Module: List + +The `List` module contains various utilities for working with type-level +tuples. It provides utilities such as mapping, filtering, and reducing +operations. + + +```ts +import { $, List, String } from 'hkt-toolbelt' + +type Result = $ // ['FOO', 'BAR'] +``` + + +| Utility name | Description | +| -- | -- | + | [Accumulate](#utility-listaccumulate) | `Accumulate` is a type-level function that takes in three inputs: a) a partially-applied type-level function for a pairwise operation that is expecting two more arguments, b) a type specifying the initial argument that will be passed into this partially-applied function, c) a target list of types, and returns a list which contains the result of every intermediate accumulator value computed while performing a reduce operation on the input list (also known as "cumulative fold"). | + | [At](#utility-listat) | `At` is a type-level function that retrieves and returns an element from a tuple type. | + | [Chunk](#utility-listchunk) | `Chunk` is a type-level function that takes in a number `N` and a list `T`, and returns a list of lists, where each sublist has a length of `N`. | + | [Concat](#utility-listconcat) | `Concat` is a type-level function that concatenates two tuples. | + | [Contains](#utility-listcontains) | `Contains` is a type-level function that takes in a value `X` and a list `T`, and returns a boolean indicating whether `X` is present in `T`. | + | [ContainsValue](#utility-listcontainsvalue) | `ContainsValue` is a type-level function that takes in a list `T` and a value `X`, and returns a boolean indicating whether `T` contains `X`. | + | [Duplicates](#utility-listduplicates) | `Duplicates` is a type-level function that takes in a list `T` and returns a list of the duplicate elements in `T`, i.e. those elements that appear more than once in `T`. | + | [Every](#utility-listevery) | `Every` is a type-level function that checks if every element in a tuple satisfies a predicate. | + | [Filter](#utility-listfilter) | `Filter` is a type-level function that takes in two inputs: a partially-applied type-level predicate that expects one more argument and returns a boolean type, and a target list of types upon which to perform the filtering operation. It returns a filtered list of types. | + | [Find](#utility-listfind) | `Find` is a type-level function that finds the first element in a list that satisfies a predicate. | + | [First](#utility-listfirst) | `First` is a type-level function that returns the first element of a tuple. | + | [FlatMap](#utility-listflatmap) | `FlatMap` is a type-level function that applies a mapping function to each element of a list, and returns a flattened list of the results (by one level only). | + | [FlattenN](#utility-listflattenn) | `FlattenN` is a type-level function that flattens a tuple up to a specified depth level by recursively concatenating nested subtuple elements. | + | [Flatten](#utility-listflatten) | `Flatten` is a type-level function that completely flattens a tuple by recursively concatenating all nested elements. | + | [Includes](#utility-listincludes) | `Includes` is a type-level function that checks if a list includes a certain element. | + | [Intersect](#utility-listintersect) | `Intersect` is a type-level function that takes in two lists `A` and `B`, and returns a list of the elements that are common to both lists. | + | [IntersectMask](#utility-listintersectmask) | `IntersectMask` is a type-level function that takes in two lists `A` and `B`, and masks out (i.e. sets to `never`) the elements in `A` that are not present in `B`. | + | [InverseMapN](#utility-listinversemapn) | `InverseMapN` is a type-level function that takes in two inputs: a list of type-level functions upon which to perform the map operation, and a target list of arguments which will be passed into all of these functions using `$N` It returns a list filled with the returned results of applying the functions to the arguments. | + | [InverseMap](#utility-listinversemap) | `InverseMap` is a type-level function that takes in two inputs: a list of type-level functions upon which to perform the map operation, and a target type argument which will be passed into all of these functions. It returns a list filled with the returned results of applying the functions to the argument. | + | [IsVariadic](#utility-listisvariadic) | `IsVariadic` is a type-level function that checks if a tuple is variadic. | + | [Iterate](#utility-listiterate) | `Iterate` is a type-level function that repeatedly applies a function over an input value for a given number of times, and returns a list containing all of the intermediate results. | + | [Last](#utility-listlast) | `Last` is a type-level function that returns the last element of a tuple. | + | [Length](#utility-listlength) | `Length` is a type-level function that returns the length of a list. | + | [List](#utility-listlist) | | + | [MapN](#utility-listmapn) | `_$MapN` is a type-level function that takes in two inputs: a partially-applied type-level function that expects more arguments, and a target list of lists upon which to map the function using the `$N` operator. It returns a mapped list of types. | + | [Map](#utility-listmap) | `Map` is a type-level function that maps a type-level function over a list of types. | + | [Pair](#utility-listpair) | `Pair` is a type-level function that generates a tuple of pairs from a tuple, where each element is paired with the next element. | + | [PopN](#utility-listpopn) | `PopN` is a type-level function that pops N elements from the tail of a list. | + | [Pop](#utility-listpop) | `Pop` is a type-level function that pops one element from the tail of a list. | + | [Push](#utility-listpush) | `Push` is a type-level function that pushes an element to the end of a tuple. | + | [PushValue](#utility-listpushvalue) | `PushValue` is a type-level function that takes in a tuple `T` and a value `U`, and returns a new tuple with `U` appended to the end of `T`. | + | [Range](#utility-listrange) | `Range` is a type-level function that generates a range of numbers. | + | [Reduce](#utility-listreduce) | `Reduce` is a type-level function that takes in three inputs: a) a partially-applied type-level function for a pairwise operation that is expecting two more arguments, b) a type specifying the initial argument that will be passed into this partially-applied function, c) a target list of types, and performs a reduce operation (also known as "fold") over the target list, and returns the resulting type. | + | [Remove](#utility-listremove) | `Remove` is a type-level function that takes in a list `T` and a value `X`, and returns a new list `T` with all instances of the value `X` removed. | + | [Repeat](#utility-listrepeat) | `Repeat` is a type-level function that returns a tuple filled with multiple elements of a specified type. | + | [Reverse](#utility-listreverse) | `Reverse` is a type-level function that reverses a tuple. | + | [ShiftN](#utility-listshiftn) | `ShiftN` is a type-level function that shifts N elements from the head of an array. | + | [Shift](#utility-listshift) | `Shift` is a type-level function that shifts one element from the head of a list. | + | [Slice](#utility-listslice) | `Slice` is a type-level function that extracts and returns a subtuple of specified range from a tuple type. It takes in three arguments: `START` and `END`, which respectively specify the inclusive start and exclusive end indices of a slice, and `T`, the tuple that is to be sliced. Both positive and negative indices are supported, with negative indices being normalized into zero-based indices under the hood. | + | [Some](#utility-listsome) | `Some` is a type-level function that checks if some element in a tuple satisfies a predicate. | + | [Splice](#utility-listsplice) | `Splice` is a type-level function that changes the contents of a tuple type by removing or replacing existing elements and/or adding new elements. | + | [Times](#utility-listtimes) | `Times` is a type-level function that generates a list of numbers from 0 to N-1. | + | [Unique](#utility-listunique) | | + | [Unshift](#utility-listunshift) | `List.Unshift` is a type-level function that prepends an item to a list. | + | [Zip](#utility-listzip) | `Zip` is a type-level function that takes in one array of arrays, `T`, and returns an array of arrays, where the i-th array contains the i-th element from each of the elements of `T`. | + + +## Utility: List.Accumulate + +`Accumulate` is a type-level function that takes in three inputs: +a) a partially-applied type-level function for a pairwise operation that is expecting two more arguments, +b) a type specifying the initial argument that will be passed into this partially-applied function, +c) a target list of types, and returns a list which contains the result of every intermediate accumulator value computed +while performing a reduce operation on the input list (also known as "cumulative fold"). + +The type-level function input must be a unary, curried `Kind` type as defined in this library, while being of arity 2 if uncurried. + +@see {@link https://github.com/poteat/hkt-toolbelt/blob/main/docs/guides/custom-kinds.md} for details on how to create a custom kind. + +| Argument name | Type | Description | +| -- | -- | -- | +| F | | A type-level function for a pairwise operation. | +| O | | A type specifying the initial argument that will be taken by `F`. | +| X | | A list of types. The target of the accumulate operation. | + + +For example, we can use `Accumulate` to derive the sum of k = 1 to n for all elements n in a list of natural number types. + +type SummationSum1to10 = $<$<$, 0>, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]>; // [1, 3, 6, 10, 15, 21, 28, 36, 45, 55] + + +We can also use the `$N` applicator to invoke `Accumulate` with a list containing the required arguments +This improves readability by allowing us to avoid nesting `$` calls three level deep. + +type IsFalse = $N; // [true, false, false, true] + + +By partially applying only the first two arguments to `Accumulate`, +we can define a type-level function that can apply the same operation to multiple list inputs. + +type GetMax = $N; +type IsZero = $; // [1, 1, 10, 10, 100, 100] + + +Another use case for a partially-applied `Accumulate` function is to implement +sophisticated higher-order functionality by passing it into other type-level functions. + +type GetMinOrJoin = $N, + $N, + $, +]>; +type IsNegativeHundred = $; // [1, -1, -1, -10, -10, -100] +type HelloWorld = $; // "hello, world" + + + +## Utility: List.At + +`At` is a type-level function that retrieves and returns an element from a tuple type. + +It takes in two arguments: a tuple, and an integer specifying the index of the element to be accessed. +Both positive and negative indices are supported, with negative indices being normalized into zero-based indices under the hood. + +| Argument name | Type | Description | +| -- | -- | -- | +| T | | A tuple type. | +| POS | | An integer type specifying the index of the element to be accessed. | + +## Edge Cases + +If `POS` is greater than or equal to the length of `T`, returns `never`. +If `POS` is lesser than the negated length of `T`, returns `never`. +If `POS` is not an integer type, returns `never`. + + +A negative index counts back from the end of the input tuple. + +type MyList = ['a', 'b', 'c', 'd', 'e']; + +type Head = $<$, MyList>; // 'a' +type Tail = $<$, MyList>; // 'e' + +type IsNever = $<$, MyList>; // never +type IsNever2 = $<$, MyList>; // never + + + +## Utility: List.Chunk + +`Chunk` is a type-level function that takes in a number `N` and a list `T`, +and returns a list of lists, where each sublist has a length of `N`. + +Trailing elements have a shorter sublist length. + +| Argument name | Type | Description | +| -- | -- | -- | +| N | | The length of each sublist. | +| T | | The list to chunk. | + + +For example, we can use `Chunk` to chunk a list into sublists of length `N`: + +```ts +import { $, List } from "hkt-toolbelt"; + +type Result = $<$, [1, 2, 3, 4, 5]>; // [[1, 2], [3, 4], [5]] +``` + + + +## Utility: List.Concat + +`Concat` is a type-level function that concatenates two tuples. + +It takes in two arguments: +`T`, the tuple to concatenate onto, and `U`, the tuple to concatenate. + +| Argument name | Type | Description | +| -- | -- | -- | +| T | | A tuple type to be concatenated onto. | +| U | | A tuple type to concatenate, or an unknown. | + +If `U` is not a tuple type, it will be pushed into `T` as its new last element. + +## Basic Usage + + +type Result = $<$, [1, 2]>; // [0, 1, 2, 3] + +## Advanced Usage + +Concatenating to a tuple with a rest parameter results in a tuple that contains the concatenated tuple. + + +type Result = $<$, [1, 2, ...string[]]>; // [1, 2, ...string[], "foo"] + + + + +## Utility: List.Contains + +`Contains` is a type-level function that takes in a value `X` and a list `T`, +and returns a boolean indicating whether `X` is present in `T`. + +| Argument name | Type | Description | +| -- | -- | -- | +| X | | The value to check. | +| T | | The list to check. | + +@returns A boolean indicating whether `X` is present in `T`. + + +For example, we can use `Contains` to check if a value is present in a list: + +```ts +import { $, List } from "hkt-toolbelt"; + +type Result = $<$, [1, 2, 3]>; // true +``` + + + +## Utility: List.ContainsValue + +`ContainsValue` is a type-level function that takes in a list `T` and a value +`X`, and returns a boolean indicating whether `T` contains `X`. + +This has opposite arguments with respect to `Contains`. + +| Argument name | Type | Description | +| -- | -- | -- | +| T | | The list to check. | +| X | | The value to check. | + +@returns A boolean indicating whether `T` contains `X`. + + +For example, we can use `ContainsValue` to check if a value is present in a list: + +```ts +import { $, List } from "hkt-toolbelt"; + +type Result = $<$, 2>; // true +``` + + + +## Utility: List.Duplicates + +`Duplicates` is a type-level function that takes in a list `T` and returns +a list of the duplicate elements in `T`, i.e. those elements that appear +more than once in `T`. + +Elements are ordered in the same order as the input list. Only the first +occurrence of each element is included in the output list. + +| Argument name | Type | Description | +| -- | -- | -- | +| T | | The list to check. | + + +For example, we can use `Duplicates` to find the duplicates in a list: + +```ts +import { $, List } from "hkt-toolbelt"; + +type Result = $<$>; // [1] +``` + + + +## Utility: List.Every + +`Every` is a type-level function that checks if every element in a tuple satisfies a predicate. + +| Argument name | Type | Description | +| -- | -- | -- | +| F | | The predicate function. | +| T | | The tuple to check. | + + +type T0 = $<$>, [1, 2, 3]> // true +type T1 = $<$>, [1, 2, 3, 'x']> // false + + + +## Utility: List.Filter + +`Filter` is a type-level function that takes in two inputs: +a partially-applied type-level predicate that expects one more argument and returns a boolean type, +and a target list of types upon which to perform the filtering operation. +It returns a filtered list of types. + +The type-level function input must be a unary, curried `Kind` type as defined in this library. + +@see {@link https://github.com/poteat/hkt-toolbelt/blob/main/docs/guides/custom-kinds.md} for details on how to create a custom kind. + +| Argument name | Type | Description | +| -- | -- | -- | +| F | | A type-level function that returns a boolean type indicating whether a type should be included in the result. | +| X | | A list of types. The target of the filtering operation. | + + +For example, we can define a filter for positive numbers and then apply it to a list: + +type FilteredNumbers = $<$, [1, -2, 3, -4]>; // [1, 3] + + +We can also use the `$N` applicator to invoke `Filter` with a list containing the required arguments +This improves readability by allowing us to avoid nesting `$` calls. + +type FilterZeros = $N, + [1, 0, 2, 0, 3] +]>; // [1, 2, 3] + + +By partially applying only the first argument to `Filter`, +we can define a type-level function that can apply the same operation to multiple list inputs. + +type FilterZeros = $>; +type AllZero = $; // [] +type OneZero = $; // [1, 2, 3, 4, 5] + + +Another use case for a partially-applied `Filter` function is to implement +sophisticated higher-order functionality by passing it into other type-level functions. + +type HelloWorld = $$<[ + $> + $ +], [42.42, null, "hello", undefined, "world"]> // "hello, world" + + + +## Utility: List.Find + +`Find` is a type-level function that finds the first element in a list that satisfies a predicate. + +| Argument name | Type | Description | +| -- | -- | -- | +| F | | The predicate function. | +| X | | The list to search. | + + +type T0 = $<$>, [1, 2, 3]> // 3 +type T1 = $<$>, [1, 2, 3]> // never + + + +## Utility: List.First + +`First` is a type-level function that returns the first element of a tuple. + +| Argument name | Type | Description | +| -- | -- | -- | +| T | | The tuple to get the first element of. | + + +type T0 = $ // 1 +type T1 = $ // never + + + +## Utility: List.FlatMap + +`FlatMap` is a type-level function that applies a mapping function to each +element of a list, and returns a flattened list of the results (by one +level only). + +Elements returned by the mapping function which are not lists will remain +in place in the flattened list. + +| Argument name | Type | Description | +| -- | -- | -- | +| F | | The type-level function to apply to each element of the list. | +| X | | The list to apply the type-level function to. | + +@returns A flattened list of the results of applying the type-level function +to each element of the list. + + + +```ts +import { $, List, String } from "hkt-toolbelt"; + +type T0 = $> // [0, 0, 1, 0, 1, 2] +``` + + + +## Utility: List.FlattenN + +`FlattenN` is a type-level function that flattens a tuple up to a specified depth level by recursively concatenating nested subtuple elements. + +| Argument name | Type | Description | +| -- | -- | -- | +| T | | The input tuple. | +| N | | Natural number specifying the depth level by which a nested tuple should be flattened. | + + +type MyList = [0, [1, [2, [3, [4]]]]] +type Result1 = $<$, MyList> // [0, 1, [2, [3, [4]]]] +type Result2 = $<$, MyList> // [0, 1, 2, [3, [4]]] +type Result3 = $<$, MyList> // [0, 1, 2, 3, 4] +type Result4 = $<$, MyList> // [0, 1, 2, 3, 4] + + + +## Utility: List.Flatten + +`Flatten` is a type-level function that completely flattens a tuple by recursively concatenating all nested elements. + +| Argument name | Type | Description | +| -- | -- | -- | +| T | | The input tuple. | + + +type MyList = [0, [1, [2, [3, [4]]]]] +type Result = $ // [0, 1, 2, 3, 4] + + + +## Utility: List.Includes + +`Includes` is a type-level function that checks if a list includes a certain +element. + +| Argument name | Type | Description | +| -- | -- | -- | +| V | | The value to check for. | +| X | | The list to check. | + + +type T0 = $<$>, [1, 2, 3]> // true +type T1 = $<$>, [1, 2, 3]> // false + + + +## Utility: List.Intersect + +`Intersect` is a type-level function that takes in two lists `A` and `B`, +and returns a list of the elements that are common to both lists. + +Elements are ordered in the same order as the first list. + +| Argument name | Type | Description | +| -- | -- | -- | +| A | | The first list. | +| B | | The second list. | +| T | | The common elements. | + + +For example, we can use `Intersect` to find the common elements in two lists: + +```ts +import { $, List } from "hkt-toolbelt"; + +type Result = $<$, [1, 3, 4, 5]>; // [1, 3] +``` + + + +## Utility: List.IntersectMask + +`IntersectMask` is a type-level function that takes in two lists `A` and `B`, +and masks out (i.e. sets to `never`) the elements in `A` that are not +present in `B`. + +Elements are ordered in the same order as the first list. + +| Argument name | Type | Description | +| -- | -- | -- | +| A | | The first list. | +| B | | The second list. | +| T | | The common elements. | + +@template T - The common elements. + + +For example, we can use `IntersectMask` to find the common elements in two lists: + +```ts +import { $, List } from "hkt-toolbelt"; + +type Result = $<$, [1, 3, 4, 5]>; // [1, never, 3] +``` + + + +## Utility: List.InverseMapN + +`InverseMapN` is a type-level function that takes in two inputs: +a list of type-level functions upon which to perform the map operation, +and a target list of arguments which will be passed into all of these functions using `$N` +It returns a list filled with the returned results of applying the functions to the arguments. + +@template T - A list of type-level functions that transform inputs and return the result. +@template X - A list of types. The arguments to be passed into every element of `T`. +@returns {List.List} A list of types resulting from the elements of `X` being inversely mapped onto `T` as arguments of the elements of `T`. + + + +## Utility: List.InverseMap + +`InverseMap` is a type-level function that takes in two inputs: +a list of type-level functions upon which to perform the map operation, +and a target type argument which will be passed into all of these functions. +It returns a list filled with the returned results of applying the functions to the argument. + +| Argument name | Type | Description | +| -- | -- | -- | +| T | | A list of type-level functions that transform unary inputs and return the result. | +| X | | A type. The argument to be passed into every element of `T`. | + +The type-level functions in `T` must be unary, curried `Kind` types as defined in this library. +@see {@link https://github.com/poteat/hkt-toolbelt/blob/main/docs/guides/custom-kinds.md} for details on how to create a custom kind. + + + +## Utility: List.IsVariadic + +`IsVariadic` is a type-level function that checks if a tuple is variadic. + +| Argument name | Type | Description | +| -- | -- | -- | +| T | | The tuple to check. | + + +type T0 = $ // true +type T1 = $ // false + + + +## Utility: List.Iterate + +`Iterate` is a type-level function that repeatedly applies a function over an input value for a given number of times, +and returns a list containing all of the intermediate results. + +| Argument name | Type | Description | +| -- | -- | -- | +| F | | The function to iterate with. | +| N | | The number of times to iterate. | +| O | | The initial input to the function. | + + +type T0 = $<$<$>, 5>, true> // [true, false, true, false, true] + + + +## Utility: List.Last + +`Last` is a type-level function that returns the last element of a tuple. + +| Argument name | Type | Description | +| -- | -- | -- | +| T | | The tuple to get the last element of. | + + +type T0 = $ // 3 +type T1 = $ // never +type T2 = $ // number +type T3 = $ // number +type T4 = $ // 'foo' +type T5 = $ // string + + + +## Utility: List.Length + +`Length` is a type-level function that returns the length of a list. + +| Argument name | Type | Description | +| -- | -- | -- | +| T | | The list to get the length of. | + + +type T0 = $ // 3 +type T1 = $ // 0 + + + +## Utility: List.List + + + + +## Utility: List.MapN + +`_$MapN` is a type-level function that takes in two inputs: +a partially-applied type-level function that expects more arguments, +and a target list of lists upon which to map the function using the `$N` operator. +It returns a mapped list of types. + +@see {@link $N} + +The type-level function input can be a fully or partially uncurried `Kind`. + +@template F - A type-level function that can be uncurried and applied to a list of arguments. +@template X - A list of lists of arguments. The target of the map operation. +@returns a mapped list of types + + + +## Utility: List.Map + +`Map` is a type-level function that maps a type-level function over a list of types. + +| Argument name | Type | Description | +| -- | -- | -- | +| T | | The type-level function to map. | +| X | | The list of types to map over. | + + +type T0 = $<$>, ['foo', 'bar']> // [true, false] +type T1 = $<$>, ['foo', 'bar']> // ['foo', 'foo'] + + + +## Utility: List.Pair + +`Pair` is a type-level function that generates a tuple of pairs from a tuple, +where each element is paired with the next element. + +| Argument name | Type | Description | +| -- | -- | -- | +| T | | The tuple to generate pairs from. | + + +type T0 = $ // [[1, 2], [2, 3], [3, 4]] +type T1 = $ // [] +type T2 = $ // [] +type T3 = $ // [[1, 2]] + + + +## Utility: List.PopN + +`PopN` is a type-level function that pops N elements from the tail of a list. + +| Argument name | Type | Description | +| -- | -- | -- | +| N | | The number of elements to pop. | +| T | | The list to pop elements from. | + + +type T0 = $<$, ['a', 'b', 'c']> // ['a', 'b'] + + + +## Utility: List.Pop + +`Pop` is a type-level function that pops one element from the tail of a list. + +| Argument name | Type | Description | +| -- | -- | -- | +| T | | The list to pop the tail element from. | + + +type T0 = $ // ['a', 'b'] + + + +## Utility: List.Push + +`Push` is a type-level function that pushes an element to the end of a tuple. + +| Argument name | Type | Description | +| -- | -- | -- | +| X | | The element to push. | +| T | | The tuple to push the element to. | + + +type T0 = $<$, [1, 2]> // [1, 2, 3] +type T1 = $<$, []> // ['foo'] + + + +## Utility: List.PushValue + +`PushValue` is a type-level function that takes in a tuple `T` and a value +`U`, and returns a new tuple with `U` appended to the end of `T`. + +This is the swapped argument order of the `List.Push` function. + +| Argument name | Type | Description | +| -- | -- | -- | +| T | | The tuple to push the value to. | +| U | | The value to push. | + + +```ts +type T0 = $<$, 4> // [1, 2, 3, 4] +``` + + + +## Utility: List.Range + +`Range` is a type-level function that generates a range of numbers. + +| Argument name | Type | Description | +| -- | -- | -- | +| START | | The start of the range. | +| STOP | | The end of the range. | +| STEP | | The step size for the range. | + + +type T0 = $<$<$, 10>, 1> // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] +type T1 = $<$<$, 0>, -2> // [10, 8, 6, 4, 2] + + + +## Utility: List.Reduce + +`Reduce` is a type-level function that takes in three inputs: +a) a partially-applied type-level function for a pairwise operation that is expecting two more arguments, +b) a type specifying the initial argument that will be passed into this partially-applied function, +c) a target list of types, and performs a reduce operation (also known as "fold") over the target list, +and returns the resulting type. + +The type-level function input must be a unary, curried `Kind` type as defined in this library, while being of arity 2 if uncurried. + +@see {@link https://github.com/poteat/hkt-toolbelt/blob/main/docs/guides/custom-kinds.md} for details on how to create a custom kind. + +| Argument name | Type | Description | +| -- | -- | -- | +| F | | A type-level function for a pairwise operation. | +| O | | A type specifying the initial argument that will be taken by `F`. | +| X | | A list of types. The target of the reduce operation. | + + +For example, we can use `Reduce` to derive the sum of all elements in a list of numeric types. + +type Sum1to10 = $<$<$, 0>, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]>; // 55 + + +We can also use the `$N` applicator to invoke `Reduce` with a list containing the required arguments +This improves readability by allowing us to avoid nesting `$` calls three level deep. + +type IsTrue = $N; // true + + +By partially applying only the first two arguments to `Reduce`, +we can define a type-level function that can apply the same operation to multiple list inputs. + +type GetMax = $N; +type IsZero = $; // 100 + + +Another use case for a partially-applied `Reduce` function is to implement +sophisticated higher-order functionality by passing it into other type-level functions. + +type GetMinOrJoin = $N, + $N, + $, +]>; + +type IsNegativeHundred = $; // -100 +type HelloWorld = $; // "hello, world" + + + +## Utility: List.Remove + +`Remove` is a type-level function that takes in a list `T` and a value `X`, +and returns a new list `T` with all instances of the value `X` removed. + +| Argument name | Type | Description | +| -- | -- | -- | +| T | | The list to remove the value from. | +| X | | The value to remove. | + + +For example, we can use `Remove` to remove the value `2` from a list: + +```ts +import { $, List } from "hkt-toolbelt"; + +type Result = $<$, [1, 2, 3, 2, 4, 2]>; // [1, 3, 4] +``` + + + +## Utility: List.Repeat + +`Repeat` is a type-level function that returns a tuple filled with multiple elements of a specified type. + +It takes in two arguments: +`T`, the type to repeat, and `N`, the number of times to repeat `T`. + +`Repeat` can handle an output tuple length of up to 2137, +which is larger than 999, the maximum recursion depth limit of TypeScript. + +| Argument name | Type | Description | +| -- | -- | -- | +| T | | An unknown type. | +| N | | A natural number. | + +If `N` is not a natural number, returns `never`. + + + +```ts +type Result = $<$, 3>; // ["a", "a", "a"] +``` + + +By partially applying a type to `Repeat` using {@see {@link $}} +we can define a type-level function that can repeat that type multiple different number of times. + +```ts +type RepeatA = $ +type RepeatATwice = $ // ["A", "A"] +type RepeatAFiveTimes = $ // ["A", "A", "A", "A", "A"] +``` + + + +## Utility: List.Reverse + +`Reverse` is a type-level function that reverses a tuple. + +| Argument name | Type | Description | +| -- | -- | -- | +| T | | The tuple to reverse. | + + +type T0 = $ // [3, 2, 1] + + + +## Utility: List.ShiftN + +`ShiftN` is a type-level function that shifts N elements from the head of an array. + +| Argument name | Type | Description | +| -- | -- | -- | +| N | | The number of elements to shift. | +| T | | The array to shift elements from. | + + +type T0 = $<$, ['a', 'b', 'c']> // ['b', 'c'] +type T1 = $<$, ['a', 'b', 'c']> // ['c'] + + + +## Utility: List.Shift + +`Shift` is a type-level function that shifts one element from the head of a list. + +| Argument name | Type | Description | +| -- | -- | -- | +| T | | The list to remove the head from. | + + +type T0 = $ // ['b', 'c'] +type T1 = $ // ['c'] + + + +## Utility: List.Slice + +`Slice` is a type-level function that extracts and returns a subtuple of specified range from a tuple type. +It takes in three arguments: `START` and `END`, which respectively specify the inclusive start and exclusive end indices of a slice, +and `T`, the tuple that is to be sliced. +Both positive and negative indices are supported, with negative indices being normalized into zero-based indices under the hood. + +| Argument name | Type | Description | +| -- | -- | -- | +| START | | An integer type. | +| END | | An integer type. | +| T | | A tuple type. | + +## Basic Usage + +We apply `Slice` to `START`, `END`, and `T` respectively using the `$` type-level applicator. + + +type MyList = ['a', 'b', 'c', 'd', 'e']; +// Slice the first two elements of `MyList`. +type Result1 = $<$<$, 2>, MyList>; // ['a', 'b'] +// Slice the last two elements of `MyList`. +type Result2 = $<$<$, 0>, MyList>; // ['d', 'e'] +// Slice the middle three elements of `MyList`. +type Result3 = $<$<$, -1>, MyList>; // ['b', 'c', 'd'] + +## Edge Cases + +If `START` or `END` is not an integer, returns `never`. +If `START >= T["length"]`, returns empty tuple. +If `START < -T["length"]` or `START` is omitted, `START` is subsituted with 0. +If `END` is greater than or equal to the length of `T`, all elements up to the end are extracted. +If `END` is positioned before or at `START` after normalization, returns empty tuple. + + + +## Utility: List.Some + +`Some` is a type-level function that checks if some element in a tuple satisfies a predicate. + +| Argument name | Type | Description | +| -- | -- | -- | +| F | | The predicate function. | +| T | | The tuple to check. | + + +type T0 = $<$>, [1, 2, 3, 'x']> // true +type T1 = $<$>, ['x', 'y', 'z']> // false + + + +## Utility: List.Splice + +`Splice` is a type-level function that changes the contents of a tuple type by removing or replacing existing elements and/or adding new elements. + +It takes in four arguments: +`T`, the tuple to splice, +`START`, the index at which to start changing the tuple. +`DEL_COUNT`, the number of elements to remove from `T` at the starting index, +`INSERTS`, an array of elements to insert into `T` at the starting index. + +Both positive and negative indices are supported for `START`. Negative indices will be normalized into zero-based indices. + +| Argument name | Type | Description | +| -- | -- | -- | +| T | | The input tuple. | +| START | | An integer representing the index at which to start splicing. | +| DEL_COUNT | | A natural number representing the number of elements to remove from T at the starting index. | +| INSERTS | | An array of elements to insert into T at the starting index. | + +## Usage + + +type MyList = [0, 1, 2, 3, 4] +type Result1 = $<$<$<$, 2>, []>, [0, 1, 2, 3, 4]>; // [0, 3, 4] +type Result2 = $<<$<$<$, 2>, ['a', 'b']>, [0, 1, 2, 3, 4]>; // [0, 'a', 'b', 3, 4] +type Result3 = $<$<$<$, 2>, ['a', 'b']>, [0, 1, 2, 3, 4]>; // [0, 1, 'a', 'b', 4] + +## Edge Cases + +If `START >= T["length"]`, no element will be deleted, but the method will behave as an adding function, adding as many elements as provided. +If `START < -T["length"]` or `START` is omitted, `START` is subsituted with 0. +If `DEL_COUNT`is greater than or equal to the number of elements after the position specified by `START`, then all the elements from `START` to the end of the array will be deleted. +If `START` is not an integer, or `DEL_COUNT` is not a natural number, returns never. + + + +## Utility: List.Times + +`Times` is a type-level function that generates a list of numbers from 0 to N-1. + +@template N - The length of the list to be generated. +@returns A list of non-negative integer types. + + + +## Utility: List.Unique + + + + +## Utility: List.Unshift + +`List.Unshift` is a type-level function that prepends an item to a list. + +| Argument name | Type | Description | +| -- | -- | -- | +| X | | The item to prepend. | +| T | | The list to prepend to. | + + +type T0 = $<$, [2, 3, 4]> // [1, 2, 3, 4] + + + +## Utility: List.Zip + +`Zip` is a type-level function that takes in one array of arrays, `T`, +and returns an array of arrays, where the i-th array contains the i-th element from each of the elements of `T`. + +The zip operation stops when the shortest sub-array is exhausted. +Any remaining items in the longer sub-array are ignored, cutting off the result to the length of the shortest sub-array. + +| Argument name | Type | Description | +| -- | -- | -- | +| T | | An array of arrays. | + + +For example, we can use `Zip` to perform parallel iteration over multiple sub-arrays. +In this example, `Zip` is a type-level function that returns an array of arrays. + +type Result = $; // [[1, "a", "A"], [2, "b", "B"]] + + + +# Module: Loop + +The `Loop` module contains various utilities for working with loops. Loops +are a type-level programming construct that allows you to repeat a block of +code until a certain condition is met. + + +```ts +import { $, NaturalNumber, Loop } from 'hkt-toolbelt' + +type Result = $< + $>, + $, + 0 +> // 11 +``` + + +| Utility name | Description | +| -- | -- | + | [Until](#utility-loopuntil) | `Until` is a type-level function that takes in a looping clause kind, an update kind, and an initial value, and returns a type that represents the result of looping until the clause is satisfied. | + + +## Utility: Loop.Until + +`Until` is a type-level function that takes in a looping clause kind, an +update kind, and an initial value, and returns a type that represents the +result of looping until the clause is satisfied. + +| Argument name | Type | Description | +| -- | -- | -- | +| Clause | | A type-level function that takes in a value and returns a | +| Updater | | A type-level function that takes in a value and returns a | +| Initial | | The initial value to start the loop with. | + + +For example, we can use `Until` to loop until a number is greater than 10: + +```ts +import { $, NaturalNumber, Loop } from "hkt-toolbelt"; + +type Result = $< + $>, + $, + 0 +>; // 11 +``` + + + +# Module: Matrix + +The `Matrix` module contains various utilities for working with matrices. +Matrices are represented as arrays of arrays, i.e. an array of rows. + + +```ts +import { $, Matrix } from 'hkt-toolbelt' + +type Result = $, + [[1, 2, 3, 4], [5, 6, 7, 8]] +>; // [[[1, 2], [3, 4]], [[5, 6], [7, 8]]] +``` + + + +## Utility: Matrix.Columns + +`Columns` is a type-level function that takes in a matrix and returns the +columns of the matrix. + +Since a matrix is represented as an array of arrays, i.e. an array of columns, +this function implements the zip function. + +| Argument name | Type | Description | +| -- | -- | -- | +| T | | The matrix to get the columns of. | + + +For example, we can use `Columns` to get the columns of a matrix: + +```ts +import { $, Matrix } from "hkt-toolbelt"; + +type Result = $; // [[1, 4], [2, 5], [3, 6]] +``` + + + +## Utility: Matrix.Combine + +`Combine` is a type-level function that takes in a matrix-of-matrices `T`, +and concatenates the matrices into a single matrix. All inner matrices must +have the same dimensions (excluding the outer dimension). + +| Argument name | Type | Description | +| -- | -- | -- | +| T | | The matrix-of-matrices to concatenate. | + + +type T0 = $ // [[[1, 2, "a", "b"], [5, 6, "e", "f"]], [[3, 4, "c", "d"], [7, 8, "g", "h"]]] +// or [[M1, M2], [M3, M4]] + + + +## Utility: Matrix.Rows + +`Rows` is a type-level function that takes in a matrix and returns the rows +of the matrix. + +Since a matrix is represented as an array of arrays, i.e. an array of rows, +this function implements the identity function. + +| Argument name | Type | Description | +| -- | -- | -- | +| T | | The matrix to get the rows of. | + + +For example, we can use `Rows` to get the rows of a matrix: + +```ts +import { $, Matrix } from "hkt-toolbelt"; + +type Result = $; // [[1, 2, 3], [4, 5, 6]] +``` + + + +## Utility: Matrix.Slice + +`Slice` is a type-level function that takes in four slice coordinates and +a matrix, and returns the slice of the matrix. Coordinates are zero-based. + +| Argument name | Type | Description | +| -- | -- | -- | +| ROW_START | | The starting row of the slice. | +| ROW_END | | The ending row of the slice. | +| COL_START | | The starting column of the slice. | +| COL_END | | The ending column of the slice. | +| T | | The matrix to get the slice of. | + + +For example, we can use `Slice` to get a slice of a matrix: + +```ts +import { $, $N, Matrix } from "hkt-toolbelt"; + +type Result = $< + $N, + [[1, 2, 3], [4, 5, 6]] +>; // [[2, 3], [5, 6]] +``` + + + +# Module: NaturalNumber + +The `NaturalNumber` module contains various utilities for working with +natural numbers, i.e. integers above or equal to zero. It provides utilities +such as addition, comparison, etc. + + +```ts +import { $, NaturalNumber } from 'hkt-toolbelt' + +type Result = $ // 6 +``` + + +| Utility name | Description | +| -- | -- | + | [Add](#utility-naturalnumberadd) | `Add` is a type-level function that takes in two natural numbers `A` and `B`, and returns the sum of the two natural numbers. | + | [Compare](#utility-naturalnumbercompare) | `Compare` is a type-level function that takes in two natural number types `A` and `B`, and returns the comparison result as a number type. The result will be 1 if `A` is greater than `B`, 0 if `A` is equal to `B`, and -1 if `A` is less than `B`. | + | [Decrement](#utility-naturalnumberdecrement) | `Decrement` is a type-level function that decrements a natural number type. It returns the decremented number. | + | [DivideBy](#utility-naturalnumberdivideby) | `DivideBy` is a type-level function that takes in two natural number types, `A` and `B`, and returns the result of dividing `B` by `A`. | + | [Divide](#utility-naturalnumberdivide) | `Divide` is a type-level function that takes in two natural numbers and performs a division operation. It returns the result of the division operation. | + | [Increment](#utility-naturalnumberincrement) | `Increment` is a type-level function that increments a natural number type. It returns the incremented natural number. | + | [IsEven](#utility-naturalnumberiseven) | `IsEven` is a type-level function that takes in a natural number type, `A`, and returns a boolean indicating whether `A` is an even number | + | [IsGreaterThanOrEqual](#utility-naturalnumberisgreaterthanorequal) | `IsGreaterThanOrEqual` is a type-level function that takes in two natural number types, `A` and `B`, and returns a boolean indicating whether `B` is greater than or equal to `A`. | + | [IsGreaterThan](#utility-naturalnumberisgreaterthan) | `IsGreaterThan` is a type-level function that takes in two natural number types, `A` and `B`, and returns a boolean indicating whether `B` is greater than `A`. | + | [IsLessThanOrEqual](#utility-naturalnumberislessthanorequal) | `IsLessThanOrEqual` is a type-level function that takes in two natural number types, `A` and `B`, and returns a boolean indicating whether `B` is less than or equal to `A`. | + | [IsLessThan](#utility-naturalnumberislessthan) | `IsLessThan` is a type-level function that takes in two natural number types, `A` and `B`, and returns a boolean indicating whether `B` is less than `A`. | + | [IsOdd](#utility-naturalnumberisodd) | `IsOdd` is a type-level function that takes in a natural number type, `A`, and returns a boolean indicating whether `A` is an odd number | + | [ModuloBy](#utility-naturalnumbermoduloby) | `ModuloBy` is a type-level function that takes in two natural number types, `A` and `B`, and returns the remainder of `B` divided by `A`. | + | [Modulo](#utility-naturalnumbermodulo) | `Modulo` is a type-level function that takes in two natural number types, `A` and `B`, and returns the remainder of `A` divided by `B`. | + | [Multiply](#utility-naturalnumbermultiply) | `Multiply` is a type-level function that multiplies a natural number by another natural number. It returns the result of the multiplication operation. | + | [SubtractBy](#utility-naturalnumbersubtractby) | `SubtractBy` is a type-level function that takes in two natural number types, `A` and `B`, and returns the result of subtracting `A` from `B`. | + | [Subtract](#utility-naturalnumbersubtract) | `Subtract` is a type-level function that subtracts one natural number from another. It returns the result of the subtraction. | + | [ToList](#utility-naturalnumbertolist) | Represents a type-level utility to convert a natural number into a list of its digits. The digits are represented as strings. | + + +## Utility: NaturalNumber.Add + +`Add` is a type-level function that takes in two natural numbers `A` and `B`, +and returns the sum of the two natural numbers. + +| Argument name | Type | Description | +| -- | -- | -- | +| A | `Number.Number` | A natural number to be added to. | +| B | `Number.Number` | A natural number to be added. | + +If one or more of the inputs is not zero or a natural number, an error is emitted. + + +For example, we can use `Add` to add the two natural numbers 123 and 456: + +We apply `Add` to 123 and 456 respectively using +the `$` type-level applicator: + +```ts +import { $, NaturalNumber } from "hkt-toolbelt" + +type Result = $<$, 456> // 579 +``` + + +If one of the inputs is not a natural number, `never` is returned. + +```ts +import { $, NaturalNumber } from "hkt-toolbelt"; + +type IsNever = $; // never +``` + + + +## Utility: NaturalNumber.Compare + +`Compare` is a type-level function that takes in +two natural number types `A` and `B`, and returns the comparison result as a number type. +The result will be 1 if `A` is greater than `B`, +0 if `A` is equal to `B`, and -1 if `A` is less than `B`. + +| Argument name | Type | Description | +| -- | -- | -- | +| A | `Number.Number` | A natural number to compare against. | +| B | `Number.Number` | A natural number to compare. | + +@returns {-1 | 0 | 1} + + +For example, we can use `Compare` to compare two natural numbers. +In this example, we compare 123 and 321: + +```ts +import { $, NaturalNumber } from "hkt-toolbelt"; + +type Result1 = $<$, 321>; // -1 +type Result2 = $<$, 123>; // 1 +``` + + + +## Utility: NaturalNumber.Decrement + +`Decrement` is a type-level function that decrements a natural number type. +It returns the decremented number. + +| Argument name | Type | Description | +| -- | -- | -- | +| A | `Number.Number` | The natural number to decrement. | + +If the input is not zero or a natural number, `never` is returned. + + +For example, we can use `Decrement` to decrement a natural number: + +```ts +import { $, NaturalNumber } from "hkt-toolbelt"; + +type Result = $; // 0 +``` + + +We can also use `Decrement` with zero as the input. +In this case, the output will also be zero. + +```ts +import { $, NaturalNumber } from "hkt-toolbelt"; + +type Result = $; // 0 +``` + + +If one of the inputs is not a natural number, `never` is returned. + +```ts +import { $, NaturalNumber } from "hkt-toolbelt"; + +type IsNever = $; // never +``` + + + +## Utility: NaturalNumber.DivideBy + +`DivideBy` is a type-level function that takes in two natural number types, +`A` and `B`, and returns the result of dividing `B` by `A`. + +| Argument name | Type | Description | +| -- | -- | -- | +| A | `Number.Number` | A natural number to divide by. | +| B | `Number.Number` | A natural number to be divided. | + +The parameters are reversed from `Divide`. This is useful for partial +application, i.e. to test divisibility. + + +For example, we can apply `DivideBy` to the type argument 3 using the `$` type-level applicator, +and evaluate the results of dividing multiple natural numbers by 3. + +```ts +import { $, NaturalNumber } from "hkt-toolbelt"; + +type DivideByThree = $; + +type Result1 = $; // 1 +type Result2 = $; // 2 +``` + + +If one of the inputs is not a natural number, `never` is returned. + +```ts +import { $, NaturalNumber } from "hkt-toolbelt"; + +type IsNever = $; // never +``` + + + +## Utility: NaturalNumber.Divide + +`Divide` is a type-level function that takes in two natural numbers and performs a division operation. +It returns the result of the division operation. + +| Argument name | Type | Description | +| -- | -- | -- | +| A | `Number.Number` | A natural number to divide. | +| B | `Number.Number` | A natural number to divide by. | + +If `A` is not a multiple of `B`, the quotient is returned and the remainder is thrown away. + +If either input is not a natural number, `never` is returned. + + +For example, we can use `Divide` to create a division operation that divides 10 by 2: + +```ts +import { $, NaturalNumber } from "hkt-toolbelt"; + +type Result = $<$, 2>; // 5 +``` + + +If `A` is not a multiple of `B`, only the quotient is returned. + +```ts +import { $, NaturalNumber } from "hkt-toolbelt"; + +type Result = $<$, 99>; // 1 +``` + + +If one of the inputs is not a natural number, `never` is returned. + +```ts +import { $, NaturalNumber } from "hkt-toolbelt"; + +type IsNever = $; // never +``` + + + +## Utility: NaturalNumber.Increment + +`Increment` is a type-level function that increments a natural number type. +It returns the incremented natural number. + +| Argument name | Type | Description | +| -- | -- | -- | +| A | `Number_.Number` | A natural number to increment. | + +If the input is not zero or a natural number, `never` is returned. + + +For example, we can use `Increment` to increment a natural number: + +```ts +import { $, NaturalNumber, Type } from "hkt-toolbelt"; + +type Result = $; // 11 +``` + + +If the input is not a natural number, `never` is returned. + +```ts +import { $, NaturalNumber } from "hkt-toolbelt"; + +type IsNever = $; // never +``` + + + +## Utility: NaturalNumber.IsEven + +`IsEven` is a type-level function that takes in a natural number type, +`A`, and returns a boolean indicating whether `A` is an even number + +@template {Number.Number} A - A natural number. +@returns {boolean} + + + +## Utility: NaturalNumber.IsGreaterThanOrEqual + +`IsGreaterThanOrEqual` is a type-level function that takes in two natural number +types, `A` and `B`, and returns a boolean indicating whether `B` is greater +than or equal to `A`. + +| Argument name | Type | Description | +| -- | -- | -- | +| A | `Number.Number` | The natural number to compare against. | +| B | `Number.Number` | The natural number to compare. | + +The parameters are ordered such that `IsGreaterThanOrEqual` can be partially applied +in a coherent manner. That is, we can apply `IsGreaterThanOrEqual` to `3`, and have a +function `IsGreaterThanOrEqualToThree`. + + +For example, we can use `IsGreaterThanOrEqual` to determine whether a natural number is +greater than another natural number. In this example, `3` and `4` are passed as +type arguments to the type-level function: + +We apply `IsGreaterThanOrEqual` to `3`, and then to `4` respectively using the `$` +type-level applicator: + +```ts +import { $, NaturalNumber } from "hkt-toolbelt"; + +type Result = $<$, 4>; // true +``` + + +If we apply `IsGreaterThanOrEqual` to `3` and `3`, we should expect to get `true`. + +```ts +import { $, NaturalNumber } from "hkt-toolbelt"; + +type Result = $<$, 3>; // true +``` + + +If we apply `IsGreaterThanOrEqual` to `3` and `2`, we should also expect to get +`false`. + +```ts +import { $, NaturalNumber } from "hkt-toolbelt"; + +type Result = $<$, 2>; // false +``` + + + +## Utility: NaturalNumber.IsGreaterThan + +`IsGreaterThan` is a type-level function that takes in two natural number +types, `A` and `B`, and returns a boolean indicating whether `B` is greater +than `A`. + +| Argument name | Type | Description | +| -- | -- | -- | +| A | `Number.Number` | A number to compare against. | +| B | `Number.Number` | A number to compare. | + +The parameters are ordered such that `IsGreaterThan` can be partially applied +in a coherent manner. That is, we can apply `IsGreaterThan` to `3`, and have a +function `IsGreaterThanThree`. + + +For example, we can use `IsGreaterThan` to determine whether a natural number is +greater than another natural number. In this example, `3` and `4` are passed as +type arguments to the type-level function: + +We apply `IsGreaterThan` to `3`, and then to `4` respectively using the `$` +type-level applicator: + +```ts +import { $, NaturalNumber } from "hkt-toolbelt"; + +type Result = $<$, 4>; // true +``` + + +If we apply `IsGreaterThan` to `3` and `3`, we should expect to get `false`. + +```ts +import { $, NaturalNumber } from "hkt-toolbelt"; + +type Result = $<$, 3>; // false +``` + + +If we apply `IsGreaterThan` to `3` and `2`, we should also expect to get +`false`. + +```ts +import { $, NaturalNumber } from "hkt-toolbelt"; + +type Result = $<$, 2>; // false +``` + + + +## Utility: NaturalNumber.IsLessThanOrEqual + +`IsLessThanOrEqual` is a type-level function that takes in two natural number +types, `A` and `B`, and returns a boolean indicating whether `B` is less +than or equal to `A`. + +| Argument name | Type | Description | +| -- | -- | -- | +| A | `Number.Number` | A number to compare against. | +| B | `Number.Number` | A number to compare. | + +The parameters are ordered such that `IsLessThanOrEqual` can be partially applied +in a coherent manner. That is, we can apply `IsLessThanOrEqual` to `3`, and have a +function `IsLessThanOrEqualToThree`. + + +For example, we can use `IsLessThanOrEqual` to determine whether a natural number is +less than another natural number. In this example, `3` and `2` are passed as +type arguments to the type-level function: + +We apply `IsLessThanOrEqual` to `3`, and then to `2` respectively using the `$` +type-level applicator: + +```ts +import { $, NaturalNumber } from "hkt-toolbelt"; + +type Result = $<$, 2>; // true +``` + + +If we apply `IsLessThanOrEqual` to `3` and `3`, we should expect to get `true`. + +```ts +import { $, NaturalNumber } from "hkt-toolbelt"; + +type Result = $<$, 3>; // true +``` + + +If we apply `IsLessThanOrEqual` to `3` and `4`, we should also expect to get +`false`. + +```ts +import { $, NaturalNumber } from "hkt-toolbelt"; + +type Result = $<$, 4>; // false +``` + + + +## Utility: NaturalNumber.IsLessThan + +`IsLessThan` is a type-level function that takes in two natural number +types, `A` and `B`, and returns a boolean indicating whether `B` is less +than `A`. + +| Argument name | Type | Description | +| -- | -- | -- | +| A | `Number.Number` | A natural number to compare against. | +| B | `Number.Number` | A natural number to compare. | + +The parameters are ordered such that `IsLessThan` can be partially applied +in a coherent manner. That is, we can apply `IsLessThan` to `3`, and have a +function `IsLessThanThree`. + + +For example, we can use `IsLessThan` to determine whether a natural number is +less than another natural number. In this example, `3` and `2` are passed as +type arguments to the type-level function: + +We apply `IsLessThan` to `3`, and then to `2` respectively using the `$` +type-level applicator: + +```ts +import { $, NaturalNumber } from "hkt-toolbelt"; + +type Result = $<$, 2>; // true +``` + + +If we apply `IsLessThan` to `3` and `3`, we should expect to get `false`. + +```ts +import { $, NaturalNumber } from "hkt-toolbelt"; + +type Result = $<$, 3>; // false +``` + + +If we apply `IsLessThan` to `3` and `4`, we should also expect to get +`false`. + +```ts +import { $, NaturalNumber } from "hkt-toolbelt"; + +type Result = $<$, 4>; // false +``` + + + +## Utility: NaturalNumber.IsOdd + +`IsOdd` is a type-level function that takes in a natural number type, +`A`, and returns a boolean indicating whether `A` is an odd number + +@template {Number.Number} A - A natural number. +@returns {boolean} + + + +## Utility: NaturalNumber.ModuloBy + +`ModuloBy` is a type-level function that takes in two natural number types, +`A` and `B`, and returns the remainder of `B` divided by `A`. + +| Argument name | Type | Description | +| -- | -- | -- | +| A | | The number to divide by to calculate the remainder. | +| B | | The numerator. | + +The parameters are reversed from `Modulo`. This is useful for partial +application, i.e. to test divisibility. + +## Usage Examples + + +For example, we can use `ModuloBy` to determine the remainder of a natural +number divided by another natural number. In this example, `3` and `4` are +passed as type arguments to the type-level function: + +```ts +import { $, NaturalNumber } from "hkt-toolbelt"; + +type ModuloByThree = $; + +type Result = $; // 4 % 3 = 1 +``` + + + +## Utility: NaturalNumber.Modulo + +`Modulo` is a type-level function that takes in two natural number types, +`A` and `B`, and returns the remainder of `A` divided by `B`. + +| Argument name | Type | Description | +| -- | -- | -- | +| A | | The number to divide. | +| B | | The number to divide by. | + +## Usage Examples + + +For example, we can use `Modulo` to determine the remainder of a natural +number divided by another natural number. In this example, `3` and `2` are +passed as type arguments to the type-level function: + +We apply `Modulo` to `3`, and then to `2` respectively using the `$` +type-level applicator: + +```ts +import { $, NaturalNumber } from "hkt-toolbelt"; + +type Result = $<$, 2>; // 1 +``` + + +Here we calculate the remainder of `10` divided by `3`: + +```ts +import { $, NaturalNumber } from "hkt-toolbelt"; + +type Result = $<$, 3>; // 1 +``` + + + +## Utility: NaturalNumber.Multiply + +`Multiply` is a type-level function that multiplies a natural number by another natural number. +It returns the result of the multiplication operation. + +| Argument name | Type | Description | +| -- | -- | -- | +| A | `Number.Number` | A natural number to multiply. | +| B | `Number.Number` | A natural number to multiply by. | + +If one or more of the inputs is not zero or a natural number, an error is emitted. + + +For example, we can use `Multiply` to multiply a natural number 42 by another natural number 12: + +```ts +import { $, NaturalNumber } from "hkt-toolbelt"; + +type Is504 = $<$, 42>; // 504 +``` + + +If one of the inputs is zero, the result will be zero. + +```ts +import { NaturalNumber } from "hkt-toolbelt"; + +type IsZero = $<$, 42>; // 0 +``` + + +If one of the inputs is not a natural number, `never` is returned. + +```ts +import { $, NaturalNumber } from "hkt-toolbelt"; + +type IsNever = $; // never +``` + + + +## Utility: NaturalNumber.SubtractBy + +`SubtractBy` is a type-level function that takes in two natural number types, +`A` and `B`, and returns the result of subtracting `A` from `B`. + +| Argument name | Type | Description | +| -- | -- | -- | +| A | `Number.Number` | A natural number to subtract by. | +| B | `Number.Number` | A natural number to be subtracted from. | + +The parameters are reversed from `Subtract`. This is useful for partial +application, i.e. to test divisibility. + + +For example, we can apply `SubtractBy` to the type argument 3 using the `$` type-level applicator, +and evaluate the results of subtracting multiple natural numbers by 3. + +```ts +import { $, NaturalNumber } from "hkt-toolbelt"; + +type SubtractByThree = $; + +type Result1 = $; // 0 +type Result2 = $; // 4 +``` + + +If one of the inputs is not a natural number, `never` is returned. + +```ts +import { $, NaturalNumber } from "hkt-toolbelt"; + +type IsNever = $; // never +``` + + + +## Utility: NaturalNumber.Subtract + +`Subtract` is a type-level function that subtracts one natural number from +another. It returns the result of the subtraction. + +| Argument name | Type | Description | +| -- | -- | -- | +| A | `Number.Number` | A natural number to subtract. | +| B | `Number.Number` | A natural number to subtract by. | + + +For example, we can use `Subtract` to subtract one natural number from another: + +```ts +import { $, NaturalNumber } from "hkt-toolbelt"; + +type Result = $<$, 25>; // 25 +``` + + +If `B` is larger than `A`, zero is returned. + +```ts +import { $, NaturalNumber } from "hkt-toolbelt"; + +type IsZero = $<$, 50>; // 0 +``` + + +If one of the inputs is not a natural number, `never` is returned. + +```ts +import { $, NaturalNumber } from "hkt-toolbelt"; + +type IsNever = $; // never +``` + + + +## Utility: NaturalNumber.ToList + +Represents a type-level utility to convert a natural number into a list of its digits. +The digits are represented as strings. + +| Argument name | Type | Description | +| -- | -- | -- | +| F | | The number to be converted. | + +@returns A list of digits representing the number. If the number is not a natural number, it returns `never`. + + +// Convert the number 42 into a list of digits: +type ListOfDigits = $; // This will be inferred as ['4', '2'] +// Convert the number 0 into a list of digits: +type ZeroList = $; // This will be inferred as ['0'] + + + +# Module: NaturalNumberTheory + +The `NaturalNumberTheory` module contains various novelty utilities for +computing natural number sequences and operations. It provides utilities such +as collatz, factorial, etc. + + +```ts +import { $, NaturalNumberTheory } from 'hkt-toolbelt' + +type Result = $ // 120 +``` + + +| Utility name | Description | +| -- | -- | + | [CollatzSequence](#utility-naturalnumbertheorycollatzsequence) | `CollatzSequence` is a type-level function that represents the Collatz sequence. This is a sequence of numbers generated by repeatedly applying the Collatz function, starting from a given number, until reaching 1. This sequence is generated using the FixSequence type-level function, which creates a fixed-point sequence for the Collatz function until it reaches a fixed point, which in this case is 1. | + | [Collatz](#utility-naturalnumbertheorycollatz) | `Collatz` is a type-level function that represents the Collatz function. If the input number is even, it is divided by 2. If the input number is odd, it is multiplied by 3 and then incremented by 1. | + | [Factorial](#utility-naturalnumbertheoryfactorial) | `Factorial` is a type-level function that calculates the factorial of a number. | + | [FibnonacciSequence](#utility-naturalnumbertheoryfibnonaccisequence) | `FibonacciSequence` is a type-level function that generates a sequence of Fibonacci numbers, given a desired resultant length, and an initial sequence. | + | [FizzBuzz](#utility-naturalnumbertheoryfizzbuzz) | A type-level function that returns "FizzBuzz" if the input is divisible by both 3 and 5, "Fizz" if the input is divisible by 3, "Buzz" if the input is divisible by 5, and the input otherwise. | + | [FizzBuzzSequence](#utility-naturalnumbertheoryfizzbuzzsequence) | A type-level function that returns a list of the FizzBuzz results for the first `N` natural numbers, from 1 to `N` inclusive. | + | [IsValidSudoku](#utility-naturalnumbertheoryisvalidsudoku) | A type-level function that checks if a given 2D array is a valid Sudoku puzzle. | + | [MaskInvalidSudokuPlaces](#utility-naturalnumbertheorymaskinvalidsudokuplaces) | Given a 9x9 grid of numbers, mask out all invalid Sudoku places to 'never'. | + + +## Utility: NaturalNumberTheory.CollatzSequence + +`CollatzSequence` is a type-level function that represents the Collatz sequence. +This is a sequence of numbers generated by repeatedly applying the Collatz function, +starting from a given number, until reaching 1. This sequence is generated using the FixSequence type-level function, +which creates a fixed-point sequence for the Collatz function until it reaches a fixed point, which in this case is 1. + +Note: We're "artificially" making `Collatz(1)` return `1` so that we can use the fixed sequence operation. + +| Argument name | Type | Description | +| -- | -- | -- | +| T | | The starting number of the sequence. | + + +type T0 = $ // [6, 3, 10, 5, 16, 8, 4, 2, 1] +type T1 = $ // [5, 16, 8, 4, 2, 1] + + + +## Utility: NaturalNumberTheory.Collatz + +`Collatz` is a type-level function that represents the Collatz function. +If the input number is even, it is divided by 2. +If the input number is odd, it is multiplied by 3 and then incremented by 1. + +| Argument name | Type | Description | +| -- | -- | -- | +| T | | The input number. | + + +type T0 = $ // 3 +type T1 = $ // 16 + + + +## Utility: NaturalNumberTheory.Factorial + +`Factorial` is a type-level function that calculates the factorial of a number. + +| Argument name | Type | Description | +| -- | -- | -- | +| x | | The number to calculate the factorial of. | + + +type T0 = $ // 120 +type T1 = $ // 1 + + + +## Utility: NaturalNumberTheory.FibnonacciSequence + +`FibonacciSequence` is a type-level function that generates a sequence of +Fibonacci numbers, given a desired resultant length, and an initial sequence. + + +```ts +import { $, NaturalNumberTheory } from "hkt-toolbelt"; + +type Result = $< + $, + [0, 1] +>; // [0, 1, 1, 2, 3] +``` + + + +## Utility: NaturalNumberTheory.FizzBuzz + +A type-level function that returns "FizzBuzz" if the input is divisible by +both 3 and 5, "Fizz" if the input is divisible by 3, "Buzz" if the input is +divisible by 5, and the input otherwise. + +This function uses the `Conditional.If` type-level function to encode an +if-then-else statement. + +| Argument name | Type | Description | +| -- | -- | -- | +| N | | The number to compute the FizzBuzz result for. | + + +```ts +import { $, NaturalNumberTheory } from "hkt-toolbelt" + +type R15 = $ // "FizzBuzz" +type R4 = $ // 4 +``` + + + +## Utility: NaturalNumberTheory.FizzBuzzSequence + +A type-level function that returns a list of the FizzBuzz results for the +first `N` natural numbers, from 1 to `N` inclusive. + +| Argument name | Type | Description | +| -- | -- | -- | +| N | | The number of FizzBuzz results to compute. | + + +```ts +import { $, NaturalNumberTheory } from "hkt-toolbelt" + +// ["1", "2", "Fizz", "4", "Buzz", "Fizz", "7", "8", "Fizz", "Buzz"] +type R10 = $ +``` + + + +## Utility: NaturalNumberTheory.IsValidSudoku + +A type-level function that checks if a given 2D array is a valid Sudoku +puzzle. + +A Sudoku puzzle is a 9x9 grid of numbers where each row, column, and 3x3 box +contains the numbers 1-9 exactly once. + +The number 0 represents an uncompleted cell, which is considered valid. + +@template T - The 2D array to check. + + + +## Utility: NaturalNumberTheory.MaskInvalidSudokuPlaces + +Given a 9x9 grid of numbers, mask out all invalid Sudoku places to 'never'. + + + + +# Module: Number + +The `Number` module contains various utilities for working with +including absolute values, comparisons, etc. + + +```ts +import { $, Number } from 'hkt-toolbelt' + +type Result = $ // 42 +``` + + +| Utility name | Description | +| -- | -- | + | [Absolute](#utility-numberabsolute) | `Absolute` is a type-level function that takes a number type `T`, and returns its absolute value. | + | [Compare](#utility-numbercompare) | `Compare` is a type-level function that takes in two number types `A` and `B`, and returns the comparison result as a number type. The result will be 1 if `A` is greater than `B`, 0 if `A` is equal to `B`, and -1 if `A` is less than `B`. | + | [FromString](#utility-numberfromstring) | `Number.FromString` is a type-level function that converts a string to a number. | + | [IsFractional](#utility-numberisfractional) | `Number.IsFractional` is a type-level function that checks if a number is fractional. | + | [IsGreaterThanOrEqual](#utility-numberisgreaterthanorequal) | `IsGreaterThanOrEqual` is a type-level function that takes in two number types, `A` and `B`, and returns a boolean indicating whether `B` is greater than or equal to `A`. | + | [IsGreaterThan](#utility-numberisgreaterthan) | `IsGreaterThan` is a type-level function that takes in two number types, `A` and `B`, and returns a boolean indicating whether `B` is greater than `A`. | + | [IsInteger](#utility-numberisinteger) | `Number.IsInteger` is a type-level function that checks if a number is an integer. | + | [IsLessThanOrEqual](#utility-numberislessthanorequal) | `IsLessThanOrEqual` is a type-level function that takes in two number types, `A` and `B`, and returns a boolean indicating whether `B` is less than or equal to `A`. | + | [IsLessThan](#utility-numberislessthan) | `IsLessThan` is a type-level function that takes in two number types, `A` and `B`, and returns a boolean indicating whether `B` is less than `A`. | + | [IsNatural](#utility-numberisnatural) | `Number.IsNatural` is a type-level function that checks if a number is a natural number. In mathematics, natural numbers are either defined as positive integers (1, 2, 3, ...) or non-negative integers (0, 1, 2, 3, ...). In this case, we include 0 in the set of natural numbers. | + | [Max](#utility-numbermax) | `Number.Max` is a type-level function that returns the maximum of two numbers. | + | [Min](#utility-numbermin) | `Number.Min` is a type-level function that returns the minimum of two numbers. | + | [Negate](#utility-numbernegate) | `Negate` is a type-level function that takes a number type `T`, and returns its absolute value. | + | [MAX_SAFE_INTEGER](#utility-numbermaxsafeinteger) | `MAX_SAFE_INTEGER` is a type that represents the maximum safe integer in JavaScript. | + | [MIN_SAFE_INTEGER](#utility-numberminsafeinteger) | `MIN_SAFE_INTEGER` is a type that represents the minimum safe integer in JavaScript. | + | [Number](#utility-numbernumber) | `Number` is a type that represents a number. It can be a string, a number, or a bigint. | + | [Sign](#utility-numbersign) | `Number.Sign` is a type-level function that returns the sign of a number. In this context, the sign of zero is considered positive. | + | [ToString](#utility-numbertostring) | `ToString` is a type-level function that converts a number to a string. | + + +## Utility: Number.Absolute + +`Absolute` is a type-level function that takes a number type `T`, and returns its absolute value. + +It returns `T` if T >= 0, and `-T` if T < 0. + +| Argument name | Type | Description | +| -- | -- | -- | +| T | | A number type. | + + +```ts +import { Number } from "hkt-toolbelt"; + +type Result1 = $; // 42 +type Result2 = $; // 42 +``` + + + +## Utility: Number.Compare + +`Compare` is a type-level function that takes in +two number types `A` and `B`, and returns the comparison result as a number type. +The result will be 1 if `A` is greater than `B`, +0 if `A` is equal to `B`, and -1 if `A` is less than `B`. + +| Argument name | Type | Description | +| -- | -- | -- | +| A | | A number type. | +| B | | A number type. | + + +For example, we can use `Compare` to compare two numbers. + +```ts +import { $, Number } from "hkt-toolbelt"; + +type Result1 = $<$, -321>; // 1 +type Result2 = $<$, 321>; // -1 +``` + + + +## Utility: Number.FromString + +`Number.FromString` is a type-level function that converts a string to a number. + +| Argument name | Type | Description | +| -- | -- | -- | +| T | | The string to convert to a number. | + + +type T0 = $ // 123 +type T1 = $ // never + + + +## Utility: Number.IsFractional + +`Number.IsFractional` is a type-level function that checks if a number is fractional. + +| Argument name | Type | Description | +| -- | -- | -- | +| T | | The number to check. | + + +type T0 = $ // true +type T1 = $ // false + + + +## Utility: Number.IsGreaterThanOrEqual + +`IsGreaterThanOrEqual` is a type-level function that takes in two number +types, `A` and `B`, and returns a boolean indicating whether `B` is greater +than or equal to `A`. + +| Argument name | Type | Description | +| -- | -- | -- | +| A | `Number.Number` | A number to compare against. | +| B | `Number.Number` | A number to evaluate. | + +The parameters are ordered such that `IsGreaterThanOrEqual` can be partially applied +in a coherent manner. That is, we can apply `IsGreaterThanOrEqual` to `3`, and have a +function `IsGreaterThanOrEqualToThree`. + + +For example, we can use `IsGreaterThanOrEqual` to determine whether an number is +less than or equal to another number. In this example, `-3` and `-2` are passed as +type arguments to the type-level function: + +We apply `IsGreaterThanOrEqual` to `-3`, and then to `-2` respectively using the `$` +type-level applicator: + +```ts +import { $, Number } from "hkt-toolbelt"; + +type Result = $<$, -2.9>; // true +``` + + +If we apply `IsGreaterThanOrEqual` to `-3` and `-3`, we should expect to get `true`. + +```ts +import { $, Number } from "hkt-toolbelt"; + +type Result = $<$, -3>; // true +``` + + +If we apply `IsGreaterThanOrEqual` to `-3` and `-4`, we should also expect to get +`false`. + +```ts +import { $, Number } from "hkt-toolbelt"; + +type Result = $<$, -3.1>; // false +``` + + + +## Utility: Number.IsGreaterThan + +`IsGreaterThan` is a type-level function that takes in two number +types, `A` and `B`, and returns a boolean indicating whether `B` is greater +than `A`. + +| Argument name | Type | Description | +| -- | -- | -- | +| A | `Number.Number` | A number to compare against. | +| B | `Number.Number` | A number to evaluate. | + +The parameters are ordered such that `IsGreaterThan` can be partially applied +in a coherent manner. That is, we can apply `IsGreaterThan` to `3`, and have a +function `IsGreaterThanThree`. + + +For example, we can use `IsGreaterThan` to determine whether an number is +greater than another number. In this example, `-2.9` and `-3` are passed as +type arguments to the type-level function: + +We apply `IsGreaterThan` to `-3`, and then to `-2.9` respectively using the `$` +type-level applicator: + +```ts +import { $, Number } from "hkt-toolbelt"; + +type Result = $<$, -2.9>; // true +``` + + +If we apply `IsGreaterThan` to `-3` and `-3`, we should expect to get `false`. + +```ts +import { $, Number } from "hkt-toolbelt"; + +type Result = $<$, -3>; // false +``` + + +If we apply `IsGreaterThan` to `-3` and `-3.1`, we should expect to get `false`. + +```ts +import { $, Number } from "hkt-toolbelt"; + +type Result = $<$, -3.1>; // false +``` + + + +## Utility: Number.IsInteger + +`Number.IsInteger` is a type-level function that checks if a number is an integer. + +| Argument name | Type | Description | +| -- | -- | -- | +| T | | The number to check. | + + +type T0 = $ // true +type T1 = $ // false + + + +## Utility: Number.IsLessThanOrEqual + +`IsLessThanOrEqual` is a type-level function that takes in two number +types, `A` and `B`, and returns a boolean indicating whether `B` is less +than or equal to `A`. + +| Argument name | Type | Description | +| -- | -- | -- | +| A | `Number.Number` | A number to compare against. | +| B | `Number.Number` | A number to evaluate. | + +The parameters are ordered such that `IsLessThanOrEqual` can be partially applied +in a coherent manner. That is, we can apply `IsLessThanOrEqual` to `3`, and have a +function `IsLessThanOrEqualToThree`. + + +For example, we can use `IsLessThanOrEqual` to determine whether an number is +less than or equal to another number. In this example, `-3` and `-4` are passed as +type arguments to the type-level function: + +We apply `IsLessThanOrEqual` to `-3`, and then to `-3.1` respectively using the `$` +type-level applicator: + +```ts +import { $, Number } from "hkt-toolbelt"; + +type Result = $<$, -3.1>; // true +``` + + +If we apply `IsLessThanOrEqual` to `-3` and `-3`, we should expect to get `true`. + +```ts +import { $, Number } from "hkt-toolbelt"; + +type Result = $<$, -3>; // true +``` + + +If we apply `IsLessThanOrEqual` to `-3` and `3.1`, we should also expect to get +`false`. + +```ts +import { $, Number } from "hkt-toolbelt"; + +type Result = $<$, 3.1>; // false +``` + + + +## Utility: Number.IsLessThan + +`IsLessThan` is a type-level function that takes in two number +types, `A` and `B`, and returns a boolean indicating whether `B` is less +than `A`. + +| Argument name | Type | Description | +| -- | -- | -- | +| A | `Number.Number` | A number to compare against. | +| B | `Number.Number` | A number to compare. | + +The parameters are ordered such that `IsLessThan` can be partially applied +in a coherent manner. That is, we can apply `IsLessThan` to `3`, and have a +function `IsLessThanThree`. + + +For example, we can use `IsLessThan` to determine whether an number is +less than another number. In this example, `-3.1` and `-3` are passed as +type arguments to the type-level function: + +We apply `IsLessThan` to `-3`, and then to `-3.1` respectively using the `$` +type-level applicator: + +```ts +import { $, Number } from "hkt-toolbelt"; + +type Result = $<$, -3.1>; // true +``` + + +If we apply `IsLessThan` to `-3` and `-3`, we should expect to get `false`. + +```ts +import { $, Number } from "hkt-toolbelt"; + +type Result = $<$, -3>; // false +``` + + +If we apply `IsLessThan` to `-3` and `3.1`, we should expect to get `false`. + +```ts +import { $, Number } from "hkt-toolbelt"; + +type Result = $<$, 3.1>; // false +``` + + + +## Utility: Number.IsNatural + +`Number.IsNatural` is a type-level function that checks if a number is a natural number. +In mathematics, natural numbers are either defined as positive integers (1, 2, 3, ...) or non-negative integers (0, 1, 2, 3, ...). +In this case, we include 0 in the set of natural numbers. + +| Argument name | Type | Description | +| -- | -- | -- | +| T | | The number to check. | + + +type T0 = $ // true +type T1 = $ // true +type T2 = $ // false +type T3 = $ // false + + + +## Utility: Number.Max + +`Number.Max` is a type-level function that returns the maximum of two numbers. + +| Argument name | Type | Description | +| -- | -- | -- | +| A | | The first number. | +| B | | The second number. | + + +type T0 = $<$, 2> // 2 +type T1 = $<$, 10> // 10 + + + +## Utility: Number.Min + +`Number.Min` is a type-level function that returns the minimum of two numbers. + +| Argument name | Type | Description | +| -- | -- | -- | +| A | | The first number. | +| B | | The second number. | + + +type T0 = $<$, 2> // 1 +type T1 = $<$, 10> // 5 + + + +## Utility: Number.Negate + +`Negate` is a type-level function that takes a number type `T`, and returns its absolute value. + +It returns `-T` if T >= 0, and `T` if T < 0. + +| Argument name | Type | Description | +| -- | -- | -- | +| T | | A number type. | + + +```ts +import { Number } from "hkt-toolbelt"; + +type Result1 = $; // -42 +type Result2 = $; // 42 +``` + + + +## Utility: Number.MAX_SAFE_INTEGER + +`MAX_SAFE_INTEGER` is a type that represents the maximum safe integer in JavaScript. + + + + +## Utility: Number.MIN_SAFE_INTEGER + +`MIN_SAFE_INTEGER` is a type that represents the minimum safe integer in JavaScript. + + + + +## Utility: Number.Number + +`Number` is a type that represents a number. It can be a string, a number, or a bigint. + + + + +## Utility: Number.Sign + +`Number.Sign` is a type-level function that returns the sign of a number. +In this context, the sign of zero is considered positive. + +| Argument name | Type | Description | +| -- | -- | -- | +| T | | The number to get the sign of. | + + +type T0 = $ // '+' +type T1 = $ // '-' +type T2 = $ // '+' + + + +## Utility: Number.ToString + +`ToString` is a type-level function that converts a number to a string. + +| Argument name | Type | Description | +| -- | -- | -- | +| N | | The number to convert to a string. | + + +type T0 = $ // '5' + + + +# Module: Object + +The `Object` module contains various utilities for working with +objects, including getting and setting values, merging, etc. + + +```ts +import { $, Object } from 'hkt-toolbelt' + +type Result = $ // 'foo' +``` + + +| Utility name | Description | +| -- | -- | + | [AtPathN](#utility-objectatpathn) | `AtPathN` is a type-level function that retrieves values from nested properties of an object based on a path. | + | [AtPath](#utility-objectatpath) | | + | [At](#utility-objectat) | `At` is a type-level function that returns the value at a given key in an object. | + | [DeepInputOf](#utility-objectdeepinputof) | Given a higher-kinded type `K`, returns a union of either the input of `K`, or a recursive object whose values are exclusively the input of `K`. | + | [DeepMapValues](#utility-objectdeepmapvalues) | | + | [Emplace](#utility-objectemplace) | | + | [KeyOrPath](#utility-objectkeyorpath) | | + | [Keys](#utility-objectkeys) | | + | [MapKeys](#utility-objectmapkeys) | | + | [MapValues](#utility-objectmapvalues) | | + | [Merge](#utility-objectmerge) | | + | [Paths](#utility-objectpaths) | | + | [UpdateN](#utility-objectupdaten) | `UpdateN` is a type-level function that updates nested properties of an object based on multiple paths. | + | [Update](#utility-objectupdate) | `Update` is a type-level function that updates nested properties of an object. | + | [Values](#utility-objectvalues) | | + + +## Utility: Object.AtPathN + +`AtPathN` is a type-level function that retrieves values from nested properties of an object based on a path. + + + + +## Utility: Object.AtPath + + + + +## Utility: Object.At + +`At` is a type-level function that returns the value at a given key in an object. + +| Argument name | Type | Description | +| -- | -- | -- | +| K | | The key to get the value of. | + + +type T0 = $<$, { a: 1; b: 2; c: 3 }> // 1 +type T1 = $<$, { a: 1; b: 2; c: 3 }> // 2 + + + +## Utility: Object.DeepInputOf + +Given a higher-kinded type `K`, returns a union of either the input of `K`, +or a recursive object whose values are exclusively the input of `K`. + + +$> +// number | { [key: string]: number | { [key: string]: number | { ... } } } + + + +## Utility: Object.DeepMapValues + + + + +## Utility: Object.Emplace + + + + +## Utility: Object.KeyOrPath + + + + +## Utility: Object.Keys + + + + +## Utility: Object.MapKeys + + + + +## Utility: Object.MapValues + + + + +## Utility: Object.Merge + + + + +## Utility: Object.Paths + + + + +## Utility: Object.UpdateN + +`UpdateN` is a type-level function that updates nested properties of an object based on multiple paths. + + + + +## Utility: Object.Update + +`Update` is a type-level function that updates nested properties of an object. + + + + +## Utility: Object.Values + + + + +# Module: Parser + +The `Parser` module contains various utilities for building type-level +parsers, which take in a string literal and return a type representing the +result of parsing the string. + +These utilities are particularly useful for parsing input strings and +converting them into more meaningful types. + + +```ts +import { $, Parser } from "hkt-toolbelt"; + +type Result = $< + $< + Parser.Run, + $< + Parser.Sequence, + [$, $, Parser.Letters] + > + >, + 'hello worlds' +> // ["hello", " ", "worlds"] +``` + + +| Utility name | Description | +| -- | -- | + | [Choice](#utility-parserchoice) | | + | [Letter](#utility-parserletter) | | + | [Letters](#utility-parserletters) | | + | [Many1](#utility-parsermany1) | | + | [Map](#utility-parsermap) | | + | [ObjectSequence](#utility-parserobjectsequence) | | + | [Optional](#utility-parseroptional) | | + | [Parser](#utility-parserparser) | | + | [Run](#utility-parserrun) | | + | [Sequence](#utility-parsersequence) | | + | [String](#utility-parserstring) | | + | [TakeSequence](#utility-parsertakesequence) | | + + +## Utility: Parser.Choice + + + + +## Utility: Parser.Letter + + + + +## Utility: Parser.Letters + + + + +## Utility: Parser.Many1 + + + + +## Utility: Parser.Map + + + + +## Utility: Parser.ObjectSequence + + + + +## Utility: Parser.Optional + + + + +## Utility: Parser.Parser + + + + +## Utility: Parser.Run + + + + +## Utility: Parser.Sequence + + + + +## Utility: Parser.String + + + + +## Utility: Parser.TakeSequence + + + + +# Module: Stress + +The `Stress` module contains various utilities for stress testing +type-level functions, including generating large tuples and objects. This is +used internally to ensure that type-level functions are robust and can handle +large inputs without crashing. + + +```ts +import { $, Stress, List } from 'hkt-toolbelt' + +type Result = $ // 100 +``` + + +| Utility name | Description | +| -- | -- | + | [HundredBooleanList](#utility-stresshundredbooleanlist) | | + | [HundredFalseList](#utility-stresshundredfalselist) | | + | [HundredTrueList](#utility-stresshundredtruelist) | | + | [HundredNumberList](#utility-stresshundrednumberlist) | | + | [HundredString](#utility-stresshundredstring) | | + | [HundredTuple](#utility-stresshundredtuple) | | + | [TenBooleanList](#utility-stresstenbooleanlist) | | + | [TenFalseList](#utility-stresstenfalselist) | | + | [TenTrueList](#utility-stresstentruelist) | | + | [TenNumberList](#utility-stresstennumberlist) | | + | [TenString](#utility-stresstenstring) | | + | [TenTuple](#utility-stresstentuple) | | + | [ThousandBooleanList](#utility-stressthousandbooleanlist) | | + | [ThousandFalseList](#utility-stressthousandfalselist) | | + | [ThousandTrueList](#utility-stressthousandtruelist) | | + | [ThousandNumberList](#utility-stressthousandnumberlist) | | + | [ThousandString](#utility-stressthousandstring) | | + | [ThousandTuple](#utility-stressthousandtuple) | | + + +## Utility: Stress.HundredBooleanList + + + + +## Utility: Stress.HundredFalseList + + + + +## Utility: Stress.HundredTrueList + + + + +## Utility: Stress.HundredNumberList + + + + +## Utility: Stress.HundredString + + + + +## Utility: Stress.HundredTuple + + + + +## Utility: Stress.TenBooleanList + + + + +## Utility: Stress.TenFalseList + + + + +## Utility: Stress.TenTrueList + + + + +## Utility: Stress.TenNumberList + + + + +## Utility: Stress.TenString + + + + +## Utility: Stress.TenTuple + + + + +## Utility: Stress.ThousandBooleanList + + + + +## Utility: Stress.ThousandFalseList + + + + +## Utility: Stress.ThousandTrueList + + + + +## Utility: Stress.ThousandNumberList + + + + +## Utility: Stress.ThousandString + + + + +## Utility: Stress.ThousandTuple + + + + +# Module: String + +The `String` module contains various utilities for working with +strings, including manipulating string types, joining strings, etc. + + +```ts +import { $, String } from 'hkt-toolbelt' + +type Result = $<$, 'foo'> // 'foobar' +``` + + +| Utility name | Description | +| -- | -- | + | [Append](#utility-stringappend) | `String.Append` is a type-level function that appends a suffix to a string. | + | [EndsWith](#utility-stringendswith) | `String.EndsWith` is a type-level function that checks if a string ends with a given suffix. | + | [First](#utility-stringfirst) | `String.First` is a type-level function that extracts the first character from a string. | + | [FromList](#utility-stringfromlist) | `String.FromList` is a type-level function that joins a list of strings into a single string. | + | [Includes](#utility-stringincludes) | `String.Includes` is a type-level function that checks if a string includes a given infix. | + | [Init](#utility-stringinit) | `String.Init` is a type-level function that extracts every element before the last element of a string. | + | [IsString](#utility-stringisstring) | `String.IsString` is a type-level function that checks if a type is a string. | + | [IsTemplate](#utility-stringistemplate) | `String.IsTemplate` is a type-level function that checks if a string is a template literal string. A template literal string is a string that includes embedded expressions, which will be evaluated and then converted into a resulting string. | + | [Join](#utility-stringjoin) | `String.Join` is a type-level function that joins an array of strings into a single string. | + | [Last](#utility-stringlast) | `String.Last` is a type-level function that extracts the last character from a string. | + | [Length](#utility-stringlength) | `String.Length` is a type-level function that returns the length of a string. | + | [Prepend](#utility-stringprepend) | `String.Prepend` is a type-level function that prepends a prefix to a string. | + | [Replace](#utility-stringreplace) | `String.Replace` is a type-level function that replaces all instances of a string with another string. | + | [Reverse](#utility-stringreverse) | `String.Reverse` is a type-level function that reverses the order of characters in a string. | + | [Slice](#utility-stringslice) | `String.Slice` is a type-level function that slices a string from a given index. | + | [Split](#utility-stringsplit) | `String.Split` is a type-level function that splits a string into an array of substrings. | + | [StartsWith](#utility-stringstartswith) | `String.StartsWith` is a type-level function that checks if a string starts with a given prefix. | + | [Tail](#utility-stringtail) | `String.Tail` is a type-level function that extracts every element after the first element of a string. | + | [ToList](#utility-stringtolist) | `String.ToList` is a type-level function that splits a string into a list of its characters. | + | [ToLower](#utility-stringtolower) | `String.ToLower` is a type-level function that converts a string to lowercase. | + | [ToUpper](#utility-stringtoupper) | `String.ToUpper` is a type-level function that converts a string to uppercase. | + + +## Utility: String.Append + +`String.Append` is a type-level function that appends a suffix to a string. + +| Argument name | Type | Description | +| -- | -- | -- | +| Suffix | | The string to append. | +| S | | The original string. | + + +type T0 = $<$, 'foo'> // 'foobar' +type T1 = $<$, 'foo'> // 'foo' + + + +## Utility: String.EndsWith + +`String.EndsWith` is a type-level function that checks if a string ends with a given suffix. + +| Argument name | Type | Description | +| -- | -- | -- | +| Suffix | | The suffix to check for. | +| S | | The string to check. | + + +type T0 = $<$, 'foobar'> // true +type T1 = $<$, 'foobar'> // false + + + +## Utility: String.First + +`String.First` is a type-level function that extracts the first character from a string. + +| Argument name | Type | Description | +| -- | -- | -- | +| S | | The string to extract the first character from. | + + +type T0 = $ // 'h' +type T1 = $ // '' + + + +## Utility: String.FromList + +`String.FromList` is a type-level function that joins a list of strings into a single string. + + +type T0 = $ // 'hello world' +type T1 = $ // '' + + + +## Utility: String.Includes + +`String.Includes` is a type-level function that checks if a string includes a given infix. + +| Argument name | Type | Description | +| -- | -- | -- | +| Infix | | The infix to check for. | +| S | | The string to check. | + + +type T0 = $<$, 'foobar'> // true +type T1 = $<$, 'foobar'> // false + + + +## Utility: String.Init + +`String.Init` is a type-level function that extracts every element before the last element of a string. + +| Argument name | Type | Description | +| -- | -- | -- | +| S | | The string to extract the init from. | + + +type T0 = $ // 'fo' +type T1 = $ // '' + + + +## Utility: String.IsString + +`String.IsString` is a type-level function that checks if a type is a string. + +| Argument name | Type | Description | +| -- | -- | -- | +| S | | The type to check. | + + +type T0 = $ // true +type T1 = $ // false + + + +## Utility: String.IsTemplate + +`String.IsTemplate` is a type-level function that checks if a string is a template literal string. +A template literal string is a string that includes embedded expressions, which will be evaluated and then converted into a resulting string. + +| Argument name | Type | Description | +| -- | -- | -- | +| S | | The string to check. | + + +type T0 = $ // true +type T1 = $ // false + + + +## Utility: String.Join + +`String.Join` is a type-level function that joins an array of strings into a single string. + +| Argument name | Type | Description | +| -- | -- | -- | +| D | | The delimiter to use when joining the strings. | +| T | | The array of strings to join. | + + +type T0 = $<$, ['foo', 'bar']> // 'foobar' +type T1 = $<$, ['foo', 'bar', 'qux']> // 'foo bar qux' + + + +## Utility: String.Last + +`String.Last` is a type-level function that extracts the last character from a string. + +| Argument name | Type | Description | +| -- | -- | -- | +| S | | The string to extract the last character from. | + + +type T0 = $ // 'o' +type T1 = $ // '' + + + +## Utility: String.Length + +`String.Length` is a type-level function that returns the length of a string. + +| Argument name | Type | Description | +| -- | -- | -- | +| S | | The string to get the length of. | + + +type T0 = $ // 5 +type T1 = $ // 0 + + + +## Utility: String.Prepend + +`String.Prepend` is a type-level function that prepends a prefix to a string. + +| Argument name | Type | Description | +| -- | -- | -- | +| Prefix | | The prefix to prepend. | +| S | | The string to prepend to. | + + +type T0 = $<$, 'bar'> // 'foobar' +type T1 = $<$, 'foo'> // 'foo' + + + +## Utility: String.Replace + +`String.Replace` is a type-level function that replaces all instances of a string with another string. + +| Argument name | Type | Description | +| -- | -- | -- | +| From | | The string to replace. | +| To | | The string to replace with. | +| S | | The string to replace in. | + + +type T0 = $<$<$, 'bar'>, 'foobar'> // 'barbar' +type T1 = $<$<$, ''>, 'foo'> // '' + + + +## Utility: String.Reverse + +`String.Reverse` is a type-level function that reverses the order of characters in a string. + +| Argument name | Type | Description | +| -- | -- | -- | +| S | | The string to reverse. | + + +type T0 = $ // 'oof' +type T1 = $ // '' + + + +## Utility: String.Slice + +`String.Slice` is a type-level function that slices a string from a given index. + +| Argument name | Type | Description | +| -- | -- | -- | +| N | | The index from which to start the slice. | +| S | | The string to slice. | + + +type T0 = $<$, 'hello'> // 'ello' +type T1 = $<$, 'hello'> // 'hello' + + + +## Utility: String.Split + +`String.Split` is a type-level function that splits a string into an array of substrings. + +| Argument name | Type | Description | +| -- | -- | -- | +| S | | The string to split. | +| Delimiter | | The delimiter to split the string by. | + + +type T0 = $<$, 'foobar'> // ['f', 'o', 'o', 'b', 'a', 'r'] +type T1 = $<$, 'foo bar'> // ['foo', 'bar'] + + + +## Utility: String.StartsWith + +`String.StartsWith` is a type-level function that checks if a string starts with a given prefix. + +| Argument name | Type | Description | +| -- | -- | -- | +| Prefix | | The prefix to check for. | +| S | | The string to check. | + + +type T0 = $<$, 'foobar'> // true +type T1 = $<$, 'foobar'> // false + + + +## Utility: String.Tail + +`String.Tail` is a type-level function that extracts every element after the first element of a string. + +| Argument name | Type | Description | +| -- | -- | -- | +| S | | The string to extract the tail from. | + + +type T0 = $ // 'ello' +type T1 = $ // '' + + + +## Utility: String.ToList + +`String.ToList` is a type-level function that splits a string into a list of its characters. + +| Argument name | Type | Description | +| -- | -- | -- | +| S | | The string to split. | + + +type T0 = $ // ['h', 'e', 'l', 'l', 'o'] +type T1 = $ // [] + + + +## Utility: String.ToLower + +`String.ToLower` is a type-level function that converts a string to lowercase. + +| Argument name | Type | Description | +| -- | -- | -- | +| S | | The string to convert to lowercase. | + + +type T0 = $ // 'hello' +type T1 = $ // 'world' + + + +## Utility: String.ToUpper + +`String.ToUpper` is a type-level function that converts a string to uppercase. + +| Argument name | Type | Description | +| -- | -- | -- | +| S | | The string to convert to uppercase. | + + +type T0 = $ // 'FOO' +type T1 = $ // 'BAR' + + + +# Module: Test + +The `Test` module contains various utilities for testing type-level +functions, including expecting types to be equal, etc. This is used +internally to ensure correctness. + + +```ts +import { $, Test } from 'hkt-toolbelt' + +type Result = Test.Expect // compiler error +``` + + +| Utility name | Description | +| -- | -- | + | [ExpectNot](#utility-testexpectnot) | `ExpectNot` is a type-level function that checks if a type `X` does not equal a type `V`. It causes a compiler error to be emitted if the types are equivalent. | + | [Expect](#utility-testexpect) | `Expect` is a type-level function that checks if a type `X` equals a type `V`. If `X` equals `V`, it returns `V`. If `X` does not equal `V`, it returns `V & _`. If `V` is never, it returns `X`. If `X` is never, it returns `Expect`. The purpose of this function is to cause a compiler error to be emitted if the types are not equivalent. | + + +## Utility: Test.ExpectNot + +`ExpectNot` is a type-level function that checks if a type `X` does not equal a type `V`. +It causes a compiler error to be emitted if the types are equivalent. + +| Argument name | Type | Description | +| -- | -- | -- | +| X | | The type to check. | +| V | | The type to compare with. Defaults to `false`. | + + +type T0 = ExpectNot // true +type T1 = ExpectNot // Compiler error + + + +## Utility: Test.Expect + +`Expect` is a type-level function that checks if a type `X` equals a type `V`. +If `X` equals `V`, it returns `V`. If `X` does not equal `V`, it returns `V & _`. +If `V` is never, it returns `X`. If `X` is never, it returns `Expect`. +The purpose of this function is to cause a compiler error to be emitted if the types are not equivalent. + +Finally, if `never` is provided and it doesn't match, we cause an infinite +loop error to be emitted so that the tests fail. + +| Argument name | Type | Description | +| -- | -- | -- | +| X | | The type to check. | +| V | | The type to compare with. Default is `true`. | + + +type T0 = Expect // true +type T1 = Expect // false & _ (compiler error) +type T2 = Expect // true & _ (compiler error) +type T3 = Expect // Expect (inf compiler error) + + + +# Module: Type + +The `Type` module contains various utilities for working with +types, including casting, displaying, and inferring types. + + +```ts +import { $, Type } from 'hkt-toolbelt' + +type Result = Type._$cast<42, number> // 42 +``` + + +| Utility name | Description | +| -- | -- | + | [Assert](#utility-typeassert) | `Assert` is a type-level function that casts a type `T` to a type `U`, but only if `U` is a more or less specific version of `T`. If an impossible coercion to an unrelated type is attempted, it returns `never`. | + | [Cast](#utility-typecast) | `Cast` is a type-level function that coercively downcasts a type `T` to a type `U`. Returns the narrower out of the two types. If the two types are unrelated, returns `U`. | + | [Display](#utility-typedisplay) | `Display` is a type-level function that forces the compiler to resolve types such that IDEs can display them on hover. | + | [Infer](#utility-typeinfer) | `Infer` is a type-level function that infers the most specific type of a value. | + | [Intersect](#utility-typeintersect) | `Intersect` is a type-level function that takes two types `A` and `B`, and returns the intersection of `A` and `B`. | + | [IntersectAll](#utility-typeintersectall) | `IntersectAll` is a type-level function that takes a tuple of types `T`, and returns the intersection of all types in `T`. | + | [IsNever](#utility-typeisnever) | `IsNever` is a type-level function that checks if a type is `never`. | + | [Union](#utility-typeunion) | `Union` is a type-level function that takes two types `A` and `B`, and returns the union of `A` and `B`. | + | [UnionAll](#utility-typeunionall) | `UnionAll` is a type-level function that takes a tuple of types `T`, and returns the union of all types in `T`. | + | [ValueOf](#utility-typevalueof) | `ValueOf` is a type-level function that extracts the values associated with the type, if any exist, via `keyof`. For arrays, values consist of their elements, while for objects, values consist of the values associated with each key. In both circumstances, we receive a union of all possible entries. | + + +## Utility: Type.Assert + +`Assert` is a type-level function that casts a type `T` to a type `U`, but only if `U` is a more or less specific version of `T`. +If an impossible coercion to an unrelated type is attempted, it returns `never`. + +This behavior is modeled after TypeScript's type assertion using the `as` operator. + +@see {@link Type._$cast} for a more permissive version of this function that only performs downcasts or coercions to unrelated types. + +| Argument name | Type | Description | +| -- | -- | -- | +| T | | The type to assert. | +| U | | The type to assert to. | + + +type T0 = $<$, true> // true +type T1 = $<$, true> // true +type T2 = $<$, boolean> // boolean +type T3 = $<$, 0> // never + + + +## Utility: Type.Cast + +`Cast` is a type-level function that coercively downcasts a type `T` to a type `U`. +Returns the narrower out of the two types. If the two types are unrelated, returns `U`. + +| Argument name | Type | Description | +| -- | -- | -- | +| T | | The type to cast. | +| U | | The type to cast to. | + + +type T0 = $<$, true> // true +type T1 = $<$, true> // true +type T2 = $<$, boolean> // true +type T3 = $<$, 0> // 0 + + + +## Utility: Type.Display + +`Display` is a type-level function that forces the compiler to resolve +types such that IDEs can display them on hover. + +| Argument name | Type | Description | +| -- | -- | -- | +| T | | The type to be displayed. | + + +type T0 = $ // 'foo' + + + +## Utility: Type.Infer + +`Infer` is a type-level function that infers the most specific type of a value. + +| Argument name | Type | Description | +| -- | -- | -- | +| X | | The value to infer the type of. | + + +type T0 = $ // 'foo' + + +// Demonstrating usage of Infer for const parameters in functions +function inferType(x: $): typeof x { + return x +} + +const x = inferType(['foo', { x: ['x'] }, 'bar', ['foo']]) +// x is inferred as ['foo', { x: ['x'] }, 'bar', ['foo']] + + + +## Utility: Type.Intersect + +`Intersect` is a type-level function that takes two types `A` and `B`, and +returns the intersection of `A` and `B`. + +| Argument name | Type | Description | +| -- | -- | -- | +| A | | The first type to intersect. | +| B | | The second type to intersect. | + + +```ts +type T0 = $ // [] & number +type T1 = $ // string +``` + + + +## Utility: Type.IntersectAll + +`IntersectAll` is a type-level function that takes a tuple of types `T`, and +returns the intersection of all types in `T`. + +| Argument name | Type | Description | +| -- | -- | -- | +| T | | The tuple of types to intersect. | + + +```ts +type T0 = $ // number & string +type T1 = $ // string +``` + + + +## Utility: Type.IsNever + +`IsNever` is a type-level function that checks if a type is `never`. + +| Argument name | Type | Description | +| -- | -- | -- | +| X | | The type to check. | + + +type T0 = $ // false +type T1 = $ // true +type T2 = $ // false +type T3 = $ // false + + + +## Utility: Type.Union + +`Union` is a type-level function that takes two types `A` and `B`, and +returns the union of `A` and `B`. + +| Argument name | Type | Description | +| -- | -- | -- | +| A | | The first type to union. | +| B | | The second type to union. | + + +```ts +type T0 = $ // number +type T1 = $ // string +``` + + + +## Utility: Type.UnionAll + +`UnionAll` is a type-level function that takes a tuple of types `T`, and +returns the union of all types in `T`. + +| Argument name | Type | Description | +| -- | -- | -- | +| T | | The tuple of types to union. | + + +```ts +type T0 = $ // number | string +type T1 = $ // string +``` + + + +## Utility: Type.ValueOf + +`ValueOf` is a type-level function that extracts the values associated +with the type, if any exist, via `keyof`. For arrays, values consist of their +elements, while for objects, values consist of the values associated with each key. +In both circumstances, we receive a union of all possible entries. + +| Argument name | Type | Description | +| -- | -- | -- | +| T | | The type to extract values from. | + + +type T0 = $ // 'foo' | 'bar' +type T1 = $ // 'foo' | 'bar' + + + +# Module: Union + +The `Union` module contains various utilities for working with union types, +including converting to intersections, lists, etc. + + +```ts +import { $, Union } from 'hkt-toolbelt' + +type Result = $ // 3 +``` + + +| Utility name | Description | +| -- | -- | + | [FromList](#utility-unionfromlist) | `Union.FromList` is a type-level function that converts a list to a union. | + | [Length](#utility-unionlength) | `Union.Length` is a type-level function that returns the length of a union. Notably, for 'boolean', the length is 2 due to it being `true | false`. | + | [ToIntersection](#utility-uniontointersection) | `ToIntersection` is a type-level function that converts a type to an intersection type. An intersection type combines multiple types into one. This allows you to add together existing types to get a single type that has all the features you need. | + | [ToList](#utility-uniontolist) | `ToList` is a type-level function that converts a union type to a list (tuple) type. | + + +## Utility: Union.FromList + +`Union.FromList` is a type-level function that converts a list to a union. + +| Argument name | Type | Description | +| -- | -- | -- | +| T | | The list to convert to a union. | + + +type T0 = $ // 1 | 2 | 3 +type T1 = $ // never + + + +## Utility: Union.Length + +`Union.Length` is a type-level function that returns the length of a union. +Notably, for 'boolean', the length is 2 due to it being `true | false`. + +| Argument name | Type | Description | +| -- | -- | -- | +| T | | The union to get the length of. | + + +type T0 = $ // 3 +type T1 = $ // 0 +type T2 = $ // 2 + + + +## Utility: Union.ToIntersection + +`ToIntersection` is a type-level function that converts a type to an intersection type. +An intersection type combines multiple types into one. This allows you to add together existing types to get a single type that has all the features you need. + +| Argument name | Type | Description | +| -- | -- | -- | +| T | | The type to convert to an intersection type. | + + +type T0 = $ // { a: 'foo'; b: 'foo' } + + + +## Utility: Union.ToList + +`ToList` is a type-level function that converts a union type to a list (tuple) type. + +| Argument name | Type | Description | +| -- | -- | -- | +| T | | The union type to convert to a list. | + + +type T0 = $ // [1, 2, 3] +type T1 = $ // [string, false, true] + + diff --git a/docs/readme.template.md b/docs/readme.template.md new file mode 100644 index 000000000..311e666e6 --- /dev/null +++ b/docs/readme.template.md @@ -0,0 +1,51 @@ +# HKT Toolbelt + +The HKT Toolbelt is a collection of type-level utilities that can be mapped and combined in functional ways using higher-kinded types. + +For example, you can map and pipe type-level functions: + +```ts +import { $, List, String } from 'hkt-toolbelt' + +type Result = $< + List.Map, + ['foo', 'bar'] // ['FOO', 'BAR'] +> +``` + +We provide utilities around string manipulation, object mapping, arithmetic, looping, parsing, and more. + +The toolbelt has {{numberOfUtilities}} utilities organized into {{numberOfModules}} modules. + +# Module List + +| Module name | Description | +| -- | -- | +{{#modules}} +| [{{name}}]({{#slug}}#module-{{slug}}{{/slug}}{{^slug}}#module{{/slug}}) | {{{shortDescription}}} | +{{/modules}} + +{{#modules}} + +# Module: {{{name}}} + +{{{fullDescription}}} + +| Utility name | Description | +| -- | -- | +{{#files}} + {{#utilities}} + | [{{name}}](#utility-{{moduleSlug}}{{slug}}) | {{{shortDescription}}} | + {{/utilities}} +{{/files}} + +{{#files}} + {{#utilities}} + +## Utility: {{moduleName}}.{{name}} + +{{{fullDescription}}} + + {{/utilities}} +{{/files}} +{{/modules}} \ No newline at end of file From b9d6605ba0f29240ec45722803dc198302100102 Mon Sep 17 00:00:00 2001 From: poteat Date: Mon, 23 Sep 2024 18:04:15 -0700 Subject: [PATCH 04/17] feat: add readme gen logic using mustache and ast walking --- scaffolding/generate-readme.ts | 44 ++++++++++++ scaffolding/tsconfig.json | 6 +- scaffolding/types/ModuleInfo.ts | 69 +++++++++++++++++++ scaffolding/utilities/ast/getJSDoc.ts | 35 ++++++++++ scaffolding/utilities/ast/isExported.ts | 12 ++++ .../utilities/ast/processFileVisitor.ts | 38 ++++++++++ .../utilities/formatting/formatJSDoc.ts | 9 +++ .../formatting/markdown/escapeForMarkdown.ts | 6 ++ .../markdown/generateMarkdownSlug.ts | 11 +++ .../markdown/renderMarkdownTable.ts | 20 ++++++ .../markdown/replaceTemplateBlockWithTable.ts | 17 +++++ .../utilities/formatting/pathToModuleName.ts | 10 +++ .../utilities/formatting/types/TemplateTag.ts | 18 +++++ scaffolding/utilities/object/mergeViaKey.ts | 30 ++++++++ .../utilities/parsing/parseTemplateTags.ts | 26 +++++++ scaffolding/utilities/string/pascalCase.ts | 13 ++++ scaffolding/visitors/getModuleInfo.ts | 33 +++++++++ scaffolding/visitors/getUtilitiesInfo.ts | 58 ++++++++++++++++ 18 files changed, 453 insertions(+), 2 deletions(-) create mode 100644 scaffolding/generate-readme.ts create mode 100644 scaffolding/types/ModuleInfo.ts create mode 100644 scaffolding/utilities/ast/getJSDoc.ts create mode 100644 scaffolding/utilities/ast/isExported.ts create mode 100644 scaffolding/utilities/ast/processFileVisitor.ts create mode 100644 scaffolding/utilities/formatting/formatJSDoc.ts create mode 100644 scaffolding/utilities/formatting/markdown/escapeForMarkdown.ts create mode 100644 scaffolding/utilities/formatting/markdown/generateMarkdownSlug.ts create mode 100644 scaffolding/utilities/formatting/markdown/renderMarkdownTable.ts create mode 100644 scaffolding/utilities/formatting/markdown/replaceTemplateBlockWithTable.ts create mode 100644 scaffolding/utilities/formatting/pathToModuleName.ts create mode 100644 scaffolding/utilities/formatting/types/TemplateTag.ts create mode 100644 scaffolding/utilities/object/mergeViaKey.ts create mode 100644 scaffolding/utilities/parsing/parseTemplateTags.ts create mode 100644 scaffolding/utilities/string/pascalCase.ts create mode 100644 scaffolding/visitors/getModuleInfo.ts create mode 100644 scaffolding/visitors/getUtilitiesInfo.ts diff --git a/scaffolding/generate-readme.ts b/scaffolding/generate-readme.ts new file mode 100644 index 000000000..69626f065 --- /dev/null +++ b/scaffolding/generate-readme.ts @@ -0,0 +1,44 @@ +import * as fs from 'fs' +import { mergeViaKey } from './utilities/object/mergeViaKey' +import { getModuleInfo } from './visitors/getModuleInfo' +import { getUtilitiesInfo } from './visitors/getUtilitiesInfo' + +import Mustache from 'mustache' +import { escapeForMarkdown } from './utilities/formatting/markdown/escapeForMarkdown' + +async function main() { + const moduleInfo = await getModuleInfo() + const utilitiesInfo = await getUtilitiesInfo() + + const mergedUtilitiesInfo = mergeViaKey(moduleInfo, utilitiesInfo, 'name') + + const template = await fs.promises.readFile( + './docs/readme.template.md', + 'utf-8' + ) + + Mustache.escape = escapeForMarkdown + + const numberOfModules = Object.keys(mergedUtilitiesInfo).length + + const numberOfUtilities = mergedUtilitiesInfo.reduce( + (acc, module) => + acc + module.files.reduce((acc, file) => acc + file.utilities.length, 0), + 0 + ) + + const rendered = Mustache.render(template, { + modules: mergedUtilitiesInfo, + numberOfModules, + numberOfUtilities + }) + + await fs.promises.writeFile( + './docs/utilities.json', + JSON.stringify(mergedUtilitiesInfo, null, 2) + ) + + await fs.promises.writeFile('./docs/readme.md', rendered) +} + +main().catch(console.error) diff --git a/scaffolding/tsconfig.json b/scaffolding/tsconfig.json index bec4092d4..cdc76b3aa 100644 --- a/scaffolding/tsconfig.json +++ b/scaffolding/tsconfig.json @@ -15,5 +15,7 @@ "forceConsistentCasingInFileNames": false, "strict": true }, - "exclude": ["node_modules"] -} + "exclude": [ + "node_modules" + ] +} \ No newline at end of file diff --git a/scaffolding/types/ModuleInfo.ts b/scaffolding/types/ModuleInfo.ts new file mode 100644 index 000000000..c9f077271 --- /dev/null +++ b/scaffolding/types/ModuleInfo.ts @@ -0,0 +1,69 @@ +/** + * Information about a module in the library, used for generating documentation. + */ +export type ModuleInfo = { + /** + * Name of the module, e.g. `List`. + */ + name: string + + /** + * Short description of the module, formed via the first paragraph of the + * JSDoc comment. + */ + shortDescription?: string + + /** + * Full description of the module, formed via the full JSDoc comment. + */ + fullDescription?: string + + /** + * Slug associated with the module, for Markdown links. + */ + slug: string + + /** + * Source files which comprise the module. + */ + files: { + /** + * Path of the utility file, e.g. 'src/list/append.ts'. + */ + path: string + + utilities: { + /** + * Name of the utility, e.g. `Append`, `_$append`, etc. + */ + name: string + + /** + * Description of the utility, formed via the first paragraph of the + * corresponding JSDoc comment. + */ + shortDescription?: string + + /** + * Full description of the utility, formed via the full JSDoc comment. + */ + fullDescription?: string + + /** + * Name of the module to which the utility belongs, e.g. `List`. + */ + moduleName: string + + /** + * Slug associated with the utility, for Markdown links. + */ + slug: string + + /** + * Slug associated with the module to which the utility belongs, for + * Markdown links. + */ + moduleSlug: string + }[] + }[] +} diff --git a/scaffolding/utilities/ast/getJSDoc.ts b/scaffolding/utilities/ast/getJSDoc.ts new file mode 100644 index 000000000..d17e80fcd --- /dev/null +++ b/scaffolding/utilities/ast/getJSDoc.ts @@ -0,0 +1,35 @@ +import ts from 'typescript' + +/** + * Extracts the JSDoc comments and tags from a given node, as a unified string, + * excluding the leading '*' for each line. + * + * @param node - The node to extract the JSDoc comments and tags from. + * + * @returns The JSDoc comments and tags as a string, or undefined if no JSDoc + * comments or tags are found. + */ +export function getJSDoc(node: ts.Node) { + const jsDocHeader = ts + .getJSDocCommentsAndTags(node) + .map((c) => ts.getTextOfJSDocComment(c.comment)) + .join('\n') + + const jsDocTags = ts + .getJSDocTags(node) + .map((t) => + t + .getText() + .split('\n') + .map((l) => l.replace(/^ \* ?/, '')) + .join('\n') + ) + .join('') + + const jsDocValue = + jsDocHeader.length > 0 || jsDocTags.length > 0 + ? [jsDocHeader, jsDocTags].join('\n\n') + : undefined + + return jsDocValue +} diff --git a/scaffolding/utilities/ast/isExported.ts b/scaffolding/utilities/ast/isExported.ts new file mode 100644 index 000000000..3b28722bc --- /dev/null +++ b/scaffolding/utilities/ast/isExported.ts @@ -0,0 +1,12 @@ +import ts from 'typescript' + +/** + * Utility function to check if a node is exported. + */ +export function isExported(node: ts.Node): boolean { + return ( + (ts.getCombinedModifierFlags(node as ts.Declaration) & + ts.ModifierFlags.Export) !== + 0 + ) +} diff --git a/scaffolding/utilities/ast/processFileVisitor.ts b/scaffolding/utilities/ast/processFileVisitor.ts new file mode 100644 index 000000000..6e1243f8e --- /dev/null +++ b/scaffolding/utilities/ast/processFileVisitor.ts @@ -0,0 +1,38 @@ +import * as fs from 'fs' +import ts from 'typescript' + +/** + * Processes a file and calls a visitor function on each node. + * + * @param filePath - The path to the file to process. + * @param visitor - The visitor function to call on each node. + * + * @returns The result of the visitor function, or undefined if no result is + * returned. + */ +export function processFileVisitor( + filePath: string, + visitor: (node: ts.Node, sourceFile: ts.SourceFile) => T | undefined +): T[] { + const sourceFile = ts.createSourceFile( + filePath, + fs.readFileSync(filePath, 'utf-8'), + ts.ScriptTarget.Latest, + true + ) + + const results: T[] = [] + + function visit(node: ts.Node) { + const visitorResult = visitor(node, sourceFile) + if (visitorResult !== undefined) { + results.push(visitorResult) + return + } + ts.forEachChild(node, visit) + } + + visit(sourceFile) + + return results +} diff --git a/scaffolding/utilities/formatting/formatJSDoc.ts b/scaffolding/utilities/formatting/formatJSDoc.ts new file mode 100644 index 000000000..71ffc9091 --- /dev/null +++ b/scaffolding/utilities/formatting/formatJSDoc.ts @@ -0,0 +1,9 @@ +import { replaceTemplateBlockWithTable } from './markdown/replaceTemplateBlockWithTable' + +/** + * Formats a JSDoc comment by removing the `@example` tag and replacing the + * `@template` tags with a Markdown table. + */ +export function formatJSDoc(content: string): string { + return replaceTemplateBlockWithTable(content.replace(/@example/g, '')) +} diff --git a/scaffolding/utilities/formatting/markdown/escapeForMarkdown.ts b/scaffolding/utilities/formatting/markdown/escapeForMarkdown.ts new file mode 100644 index 000000000..6d909d2d1 --- /dev/null +++ b/scaffolding/utilities/formatting/markdown/escapeForMarkdown.ts @@ -0,0 +1,6 @@ +/** + * Escapes a string for use in Markdown. + */ +export function escapeForMarkdown(str: string) { + return str.replace(/\$/g, '\\$') +} diff --git a/scaffolding/utilities/formatting/markdown/generateMarkdownSlug.ts b/scaffolding/utilities/formatting/markdown/generateMarkdownSlug.ts new file mode 100644 index 000000000..71a355a66 --- /dev/null +++ b/scaffolding/utilities/formatting/markdown/generateMarkdownSlug.ts @@ -0,0 +1,11 @@ +/** + * Generate a slug for a given string value. This is used to generate Markdown + * internal links. + */ + +export function generateMarkdownSlug(value: string) { + return value + .toLowerCase() + .replace(/\s/g, '-') + .replace(/[^a-z0-9-]/g, '') +} diff --git a/scaffolding/utilities/formatting/markdown/renderMarkdownTable.ts b/scaffolding/utilities/formatting/markdown/renderMarkdownTable.ts new file mode 100644 index 000000000..ad6fd722e --- /dev/null +++ b/scaffolding/utilities/formatting/markdown/renderMarkdownTable.ts @@ -0,0 +1,20 @@ +/** + * Renders a Markdown table from an array of objects. + */ + +export function renderMarkdownTable>( + data: T[] +): string { + if (data.length === 0) return '' + + const headers = Object.keys(data[0]) as (keyof T)[] + + const headerRow = `| ${headers.join(' | ')} |` + const separatorRow = `| ${headers.map(() => '--').join(' | ')} |` + + const rows = data.map( + (row) => `| ${headers.map((header) => row[header] || '').join(' | ')} |` + ) + + return [headerRow, separatorRow, ...rows].join('\n') + '\n\n' +} diff --git a/scaffolding/utilities/formatting/markdown/replaceTemplateBlockWithTable.ts b/scaffolding/utilities/formatting/markdown/replaceTemplateBlockWithTable.ts new file mode 100644 index 000000000..5e9a616ee --- /dev/null +++ b/scaffolding/utilities/formatting/markdown/replaceTemplateBlockWithTable.ts @@ -0,0 +1,17 @@ +import { parseTemplateTags } from '../../parsing/parseTemplateTags' +import { renderMarkdownTable } from './renderMarkdownTable' + +/** + * Replaces a block of `@template` tags with a Markdown table. + */ +export function replaceTemplateBlockWithTable(content: string): string { + const templateArguments = parseTemplateTags(content) + + if (templateArguments.length === 0) { + return content + } + + const markdownTable = renderMarkdownTable(templateArguments) + + return content.replace(/@template[^]*?\n\n/, markdownTable) +} diff --git a/scaffolding/utilities/formatting/pathToModuleName.ts b/scaffolding/utilities/formatting/pathToModuleName.ts new file mode 100644 index 000000000..c29ddc5e6 --- /dev/null +++ b/scaffolding/utilities/formatting/pathToModuleName.ts @@ -0,0 +1,10 @@ +import { pascalCase } from '../string/pascalCase' + +/** + * Convert a path to a module name. + * + * @example "src/string/append.ts" => "String" + */ +export function pathToModuleName(path: string) { + return pascalCase(path.split('/')[1]) || '$' +} diff --git a/scaffolding/utilities/formatting/types/TemplateTag.ts b/scaffolding/utilities/formatting/types/TemplateTag.ts new file mode 100644 index 000000000..10bf58096 --- /dev/null +++ b/scaffolding/utilities/formatting/types/TemplateTag.ts @@ -0,0 +1,18 @@ +/** + * Structure representing a template tag in a JSDoc comment. Keys are used for + * rendering as a Markdown table. + */ +export type TemplateTag = { + /** + * The name of the type argument. + */ + 'Argument name': string + /** + * The type of the type argument, i.e. what it extends, or a constraint. + */ + Type: string + /** + * The description of the type argument. + */ + Description: string +} diff --git a/scaffolding/utilities/object/mergeViaKey.ts b/scaffolding/utilities/object/mergeViaKey.ts new file mode 100644 index 000000000..2cd9da701 --- /dev/null +++ b/scaffolding/utilities/object/mergeViaKey.ts @@ -0,0 +1,30 @@ +import { keyBy } from 'lodash' + +/** + * Merge two arrays of objects via a key. Only elements which exist in both + * arrays are merged. + */ +export function mergeViaKey< + T extends Record & { + [key in K]: string + }, + U extends Record & { + [key in K]: string + }, + K extends string +>( + array1: T[], + array2: U[], + key: K +): { + [key in keyof (T & U)]: (T & U)[key] +}[] { + const array2Map = keyBy(array2, key) + + return array1 + .filter((obj1) => obj1[key] in array2Map) + .map((obj1) => ({ + ...obj1, + ...array2Map[obj1[key]] + })) +} diff --git a/scaffolding/utilities/parsing/parseTemplateTags.ts b/scaffolding/utilities/parsing/parseTemplateTags.ts new file mode 100644 index 000000000..66d0581b6 --- /dev/null +++ b/scaffolding/utilities/parsing/parseTemplateTags.ts @@ -0,0 +1,26 @@ +import { TemplateTag } from '../formatting/types/TemplateTag' + +/** + * Parses the template tags from a JSDoc comment. + */ +export function parseTemplateTags(content: string): TemplateTag[] { + const templateRegex = + /@template(?:\s+\{([^\}]+)\})?\s+([A-Za-z_][A-Za-z0-9_]*)\s+-\s+([^\n]+)\n?/g + + const templateArguments: TemplateTag[] = [] + + let match: string[] | null + while ((match = templateRegex.exec(content)) !== null) { + const [, argType, argName, argDescription] = match + + const wrapGrave = (str: string) => (str ? `\`${str}\`` : '') + + templateArguments.push({ + 'Argument name': argName.trim(), + Type: wrapGrave(argType ? argType.trim() : ''), + Description: argDescription.trim() + }) + } + + return templateArguments +} diff --git a/scaffolding/utilities/string/pascalCase.ts b/scaffolding/utilities/string/pascalCase.ts new file mode 100644 index 000000000..8d45e4e36 --- /dev/null +++ b/scaffolding/utilities/string/pascalCase.ts @@ -0,0 +1,13 @@ +import { camelCase } from 'lodash' + +/** + * Converts a string to PascalCase. + * + * @param str - The string to convert. + * + * @returns The PascalCase version of the string. + */ +export function pascalCase(str: string) { + const camel = camelCase(str) + return camel.charAt(0).toUpperCase() + camel.slice(1) +} diff --git a/scaffolding/visitors/getModuleInfo.ts b/scaffolding/visitors/getModuleInfo.ts new file mode 100644 index 000000000..0ce453169 --- /dev/null +++ b/scaffolding/visitors/getModuleInfo.ts @@ -0,0 +1,33 @@ +import { glob } from 'glob' +import ts from 'typescript' +import { getJSDoc } from '../utilities/ast/getJSDoc' +import { processFileVisitor } from '../utilities/ast/processFileVisitor' +import { formatJSDoc } from '../utilities/formatting/formatJSDoc' +import { generateMarkdownSlug } from '../utilities/formatting/markdown/generateMarkdownSlug' +import { pascalCase } from '../utilities/string/pascalCase' + +/** + * Get the module information for all modules in the library, including their + * name and description. + */ +export async function getModuleInfo() { + const files = await glob.glob('src/!(*.spec|index).ts') + + const moduleInfo = files + .flatMap((filePath) => + processFileVisitor(filePath, (node, sourceFile) => { + if (ts.isModuleDeclaration(node)) { + const name = pascalCase(node.name.getText(sourceFile)) || '$' + const fullDescription = formatJSDoc(getJSDoc(node) || '') + const shortDescription = getJSDoc(node) + ?.split('\n\n')[0] + ?.replace(/\n/g, ' ') + const slug = generateMarkdownSlug(name) + return { name, shortDescription, fullDescription, slug } + } + }) + ) + .sort((a, b) => a.name.localeCompare(b.name)) + + return moduleInfo +} diff --git a/scaffolding/visitors/getUtilitiesInfo.ts b/scaffolding/visitors/getUtilitiesInfo.ts new file mode 100644 index 000000000..10dbcecac --- /dev/null +++ b/scaffolding/visitors/getUtilitiesInfo.ts @@ -0,0 +1,58 @@ +import { glob } from 'glob' +import { chain } from 'lodash' +import ts from 'typescript' +import { getJSDoc } from '../utilities/ast/getJSDoc' +import { isExported } from '../utilities/ast/isExported' +import { processFileVisitor } from '../utilities/ast/processFileVisitor' +import { formatJSDoc } from '../utilities/formatting/formatJSDoc' +import { generateMarkdownSlug } from '../utilities/formatting/markdown/generateMarkdownSlug' +import { pathToModuleName } from '../utilities/formatting/pathToModuleName' + +/** + * Get the utility information for all utilities in the library, including their + * name, description, and source file. + */ +export async function getUtilitiesInfo() { + const files = await glob.glob('src/*/!(*.spec|index).ts') + + const utilitiesInfo = chain(files) + .map((path) => ({ + path, + utilities: processFileVisitor(path, (node, sourceFile) => { + if ( + (ts.isInterfaceDeclaration(node) || + ts.isTypeAliasDeclaration(node)) && + isExported(node) + ) { + const moduleName = pathToModuleName(path) + const name = node.name.getText(sourceFile) + const fullDescription = formatJSDoc(getJSDoc(node) || '') + const shortDescription = getJSDoc(node) + ?.split('\n\n')[0] + ?.replace(/\n/g, ' ') + const slug = generateMarkdownSlug(name) + const moduleSlug = generateMarkdownSlug(moduleName) + + return { + name, + shortDescription, + fullDescription, + moduleName, + slug, + moduleSlug + } + } + }) + .filter((x) => !x.name.startsWith('_')) + .sort((a, b) => a.name.localeCompare(b.name)) + })) + .groupBy((file) => pathToModuleName(file.path)) + .mapValues((files, name) => ({ + name, + files: files.sort((a, b) => a.path.localeCompare(b.path)) + })) + .values() + .value() + + return utilitiesInfo +} From a324a0b15135fb866465925f4d8ff36402f06f01 Mon Sep 17 00:00:00 2001 From: poteat Date: Mon, 23 Sep 2024 18:08:50 -0700 Subject: [PATCH 05/17] docs: update jsdoc for various modules --- src/$.ts | 4 ++-- src/$/$$.ts | 10 +++++----- src/$/$.ts | 12 ++++++------ src/$/$N.spec.ts | 12 ++++++++++-- src/$/$N.ts | 7 +++++-- src/boolean/and-all.ts | 10 ++++++---- src/boolean/and.ts | 8 ++++---- src/boolean/imply.ts | 8 ++++---- src/boolean/nand-all.ts | 10 ++++++---- src/boolean/nand.ts | 6 +++--- src/boolean/nimply.ts | 8 ++++---- src/boolean/nor-all.spec.ts | 4 ++++ src/boolean/nor-all.ts | 10 ++++++---- src/boolean/nor.ts | 10 +++++----- src/boolean/not.ts | 6 +++--- src/boolean/or-all.ts | 10 ++++++---- src/boolean/or.ts | 10 +++++----- src/boolean/xnor-all.ts | 18 ++++++++++-------- src/boolean/xnor.ts | 10 +++++----- src/boolean/xor.ts | 10 +++++----- src/combinator/apply-self.ts | 4 ++-- src/combinator/collate.ts | 4 ++-- src/combinator/fix-sequence.ts | 5 ++++- src/combinator/recursive-kind.ts | 4 +++- src/combinator/self.ts | 3 +++ src/conditional/equals-all.ts | 7 +++---- src/conditional/equals.spec.ts | 8 ++++++++ src/conditional/equals.ts | 27 +++++++++++++++++++++++---- src/conditional/extends-all.ts | 12 ++++++------ src/conditional/extends.ts | 8 ++++---- src/conditional/if.ts | 11 ++++++----- src/conditional/is-supertype-of.ts | 9 +++++---- src/conditional/not-equals.ts | 8 ++++---- src/digit-list.ts | 2 +- src/digit-list/multiply-digit.ts | 4 ++-- src/digit-list/multiply.ts | 3 ++- src/digit/add-tens.ts | 11 +++++------ src/digit/add.ts | 11 +++++------ src/digit/compare.ts | 10 ++++------ src/digit/decrement-tens.ts | 8 +++----- src/digit/decrement.ts | 8 +++----- src/digit/digit.ts | 21 --------------------- src/digit/increment-tens.ts | 6 +++--- src/digit/increment.ts | 6 +++--- src/digit/multiply-tens.ts | 28 +++++----------------------- src/digit/multiply.ts | 10 +++++----- src/digit/subtract-tens.ts | 10 +++++----- src/digit/subtract.ts | 10 +++++----- src/function/constant.ts | 7 ++----- src/function/identity.ts | 2 +- src/kind/apply-n.ts | 3 ++- src/kind/apply.ts | 4 ++-- src/kind/arity.ts | 4 +++- src/kind/composable-pair.ts | 15 ++++++++++++--- src/kind/input-of.spec.ts | 9 +++++++-- src/object/at.ts | 21 +++++++++++++++++++++ src/object/map-keys.ts | 10 +--------- 57 files changed, 279 insertions(+), 237 deletions(-) diff --git a/src/$.ts b/src/$.ts index 72dae7924..f1cba9fad 100644 --- a/src/$.ts +++ b/src/$.ts @@ -6,9 +6,9 @@ export * from './$/' * * @example * ```ts - * import { $, List, String } from 'hkt-toolbelt' + * import { $, String } from 'hkt-toolbelt' * - * type Result = $, ['foo', 'bar']> // ['FOO', 'BAR'] + * type Result = $ // 'FOO' * ``` */ declare module './$' {} diff --git a/src/$/$$.ts b/src/$/$$.ts index 957256a23..eefac85c9 100644 --- a/src/$/$$.ts +++ b/src/$/$$.ts @@ -4,7 +4,7 @@ import { Kind, List } from '..' * `$$` is a type-level function in `hkt-toolbelt` that allows users to pipe * multiple type-level functions together and apply them to an input. * - * ## Purpose + * ### Purpose * * `hkt-toolbelt` provides a variety of higher-order type-level functions that * enable users to create complex type-level logic. However, it can be @@ -48,10 +48,10 @@ import { Kind, List } from '..' * Here, `$$` is being used to pipe `List.Push` and `String.Join` together and * then apply them to a list of strings. * - * @template FX - A tuple of type-level functions that will be piped together. - * @template X - The input type that the type-level functions will be applied to. + * @template {Kind[]} FX - A tuple of type-level functions that will be piped together. + * @template {InputOf} X - The input type that the type-level functions will be applied to. * - * ### Basic Usage + * #### Basic Usage * * @example * Here's a basic example that uses `$$` to apply a type-level function to an @@ -69,7 +69,7 @@ import { Kind, List } from '..' * Here, `List.Push` and `List.Unshift` are being piped together using `$$` to * append "bar" to a list of numbers and then prepend "foo". * - * ## Errors + * #### Errors * * `$$` will enforce that the Nth type-level function's output is a subtype of * the (N + 1)th input. If this is not the case, `$$` will return the `never` diff --git a/src/$/$.ts b/src/$/$.ts index 9fc7b3ece..70e33a087 100644 --- a/src/$/$.ts +++ b/src/$/$.ts @@ -1,4 +1,4 @@ -import { Kind, Function } from '..' +import { Function, Kind } from '..' /** * `$` is the most fundamental type in `hkt-toolbelt`. `$` is a generic type @@ -12,7 +12,7 @@ import { Kind, Function } from '..' * type-level function to a different input type. All applications of `$` must * be curried. * - * ## Higher Order Type-Level Functions + * ### Type-Level Function Application * * The reason that we use `$` instead of normal generic type parameters is that * we want to be able to partially apply type-level functions. If we used @@ -30,10 +30,10 @@ import { Kind, Function } from '..' * normal generic type parameters. Instead, we would need to use a higher-order * type-level function. That is what `hkt-toolbelt` provides. * - * @template F - A type-level function. - * @template X - The input type to apply the type-level function to. + * @template {Kind} F - A type-level function. + * @template {InputOf} X - The input type to apply the type-level function to. * - * ### Basic Usage + * #### Basic Usage * * @example * For example, `Function.Identity` is a type-level function which takes in one @@ -70,7 +70,7 @@ import { Kind, Function } from '..' * type Result = $<$, "foo">; // "foobar" * ``` * - * ### Advanced Usage + * #### Advanced Usage * * @example * For example, `List.Map` is a type-level function which takes in two diff --git a/src/$/$N.spec.ts b/src/$/$N.spec.ts index ea25290d2..2f1495d15 100644 --- a/src/$/$N.spec.ts +++ b/src/$/$N.spec.ts @@ -1,4 +1,4 @@ -import { $, $N, Function, NaturalNumber, Conditional, Test } from '..' +import { $, $N, Conditional, Function, NaturalNumber, Test } from '..' type IsLessThan5 = $N< Conditional.If, @@ -13,5 +13,13 @@ type $N_Spec = [ /** * 4 less than 5 => yes */ - Test.Expect<$, 'yes'> + Test.Expect<$, 'yes'>, + + /** + * Type errors for wrong input types + */ + $N< + Conditional.If, + [$, 'yes', $] + > ] diff --git a/src/$/$N.ts b/src/$/$N.ts index 10772f4f2..50ce770f9 100644 --- a/src/$/$N.ts +++ b/src/$/$N.ts @@ -8,8 +8,11 @@ import { Kind } from '..' * the contrapositive of `$$`, in that `$$` pipes a value through a list of * functions, while `$N` pipes a list of values through a function. * - * @template {Kind.Kind} K - The type-level function to apply. - * @template {List.List} X - The list of arguments to apply the type-level function to. + * There is no specific type checking to ensure the elements of the list are + * subtypes of the input type of the type-level function. + * + * @template {Kind} K - The type-level function to apply. + * @template {List} X - The list of arguments to apply the type-level function to. * * Since all type-level functions are curried, we successively apply the * type-level function to each argument in the list. diff --git a/src/boolean/and-all.ts b/src/boolean/and-all.ts index 3e1db6ac3..cf2c3020d 100644 --- a/src/boolean/and-all.ts +++ b/src/boolean/and-all.ts @@ -4,7 +4,7 @@ import { Kind, Type } from '..' * `_$andAll` is a type-level function that determines whether all elements * in a sequence of booleans are `true`. * - * @template B - A sequence of booleans. + * @template T - A sequence of booleans. * * @example * For example, we can use `_$andAll` to check if all elements in a boolean @@ -29,8 +29,10 @@ type TrueList< > = Output /** - * `AndAll` is a type-level function that applies the '_$andAll' operation to - * a sequence of booleans. + * `AndAll` is a type-level function that checks whether all elements in a + * sequence of booleans are `true`. + * + * @template {boolean[]} T - The boolean array to check. * * @example * For example, we can use `AndAll` to check if all elements in a boolean array @@ -41,7 +43,7 @@ type TrueList< * ```ts * import { $, Boolean } from "hkt-toolbelt"; * - * type Result = $<$>; // true + * type Result = $; // true * ``` */ export interface AndAll extends Kind.Kind { diff --git a/src/boolean/and.ts b/src/boolean/and.ts index 55d06de1d..02022921a 100644 --- a/src/boolean/and.ts +++ b/src/boolean/and.ts @@ -6,8 +6,8 @@ import { Kind, Type } from '..' * on `T` and `U`. If both `T` and `U` are true, then `_$and` returns true, * otherwise it returns false. * - * @template T - A boolean type. - * @template U - A boolean type. + * @template {boolean} T - A boolean type. + * @template {boolean} U - A boolean type. * * @example * For example, we can use `_$and` to determine whether two boolean types are @@ -36,8 +36,8 @@ interface And_T extends Kind.Kind { * `U`, and returns the boolean result of applying the 'and' logical operation * on `T` and `U`. * - * @template T - A boolean type. - * @template U - A boolean type. + * @template {boolean} T - A boolean type. + * @template {boolean} U - A boolean type. * * @example * For example, we can use `And` to determine whether two boolean types are diff --git a/src/boolean/imply.ts b/src/boolean/imply.ts index c69117941..62dc21f24 100644 --- a/src/boolean/imply.ts +++ b/src/boolean/imply.ts @@ -8,8 +8,8 @@ import { Kind, Type } from '..' * * This is also known as the 'logical implication' operator. * - * @template T - A boolean type. - * @template U - A boolean type. + * @template {boolean} T - A boolean type. + * @template {boolean} U - A boolean type. * * @example * For example, we can use `_$imply` to determine whether a statement is true @@ -40,8 +40,8 @@ interface Imply_T extends Kind.Kind { * * This is also known as the 'logical implication' operator. * - * @template T - A boolean type. - * @template U - A boolean type. + * @template {boolean} T - A boolean type. + * @template {boolean} U - A boolean type. * * @example * For example, we can use `Imply` to determine whether a statement is true diff --git a/src/boolean/nand-all.ts b/src/boolean/nand-all.ts index 4ef47431a..f9337796d 100644 --- a/src/boolean/nand-all.ts +++ b/src/boolean/nand-all.ts @@ -1,4 +1,4 @@ -import { Kind, Type, Boolean } from '..' +import { Boolean, Kind, Type } from '..' /** * `_$nAndAll` is a type-level function that determines whether none of the @@ -24,8 +24,10 @@ export type _$nandAll = 0 extends B['length'] : true /** - * `NandAll` is a type-level function that applies the '_$nAndAll' operation to - * a sequence of booleans. + * `NandAll` is a type-level function that checks whether none of the elements + * in a sequence of boolean values are `true`. + * + * @template {boolean[]} T - The boolean array to check. * * @example * For example, we can use `NandAll` to check if none of the elements in a @@ -37,7 +39,7 @@ export type _$nandAll = 0 extends B['length'] * ```ts * import { $, Boolean } from "hkt-toolbelt"; * - * type Result = $<$>; // true + * type Result = $; // true * ``` */ export interface NandAll extends Kind.Kind { diff --git a/src/boolean/nand.ts b/src/boolean/nand.ts index c62109412..6f27a2340 100644 --- a/src/boolean/nand.ts +++ b/src/boolean/nand.ts @@ -1,4 +1,4 @@ -import { Type, Kind } from '..' +import { Kind, Type } from '..' /** * `_$nand` is a type-level function that takes in two boolean types, `T` and @@ -36,8 +36,8 @@ interface Nand_T extends Kind.Kind { * `U`, and returns the boolean result of applying the 'nand' logical operation * on `T` and `U`. * - * @template T - A boolean type. - * @template U - A boolean type. + * @template {boolean} T - A boolean type. + * @template {boolean} U - A boolean type. * * @example * For example, we can use `Nand` to determine whether two boolean types are diff --git a/src/boolean/nimply.ts b/src/boolean/nimply.ts index 3682092b9..38ddf12f0 100644 --- a/src/boolean/nimply.ts +++ b/src/boolean/nimply.ts @@ -6,8 +6,8 @@ import { Kind, Type } from '..' * operation on `T` and `U`. If `T` is true and `U` is false, then `_$nimply` * returns true, otherwise it returns false. * - * @template T - A boolean type. - * @template U - A boolean type. + * @template {boolean} T - A boolean type. + * @template {boolean} U - A boolean type. * * @example * For example, we can use `_$nimply` to determine whether two boolean types @@ -36,8 +36,8 @@ interface Nimply_T extends Kind.Kind { * `U`, and returns the boolean result of applying the 'not-implies' logical * operation on `T` and `U`. * - * @template T - A boolean type. - * @template U - A boolean type. + * @template {boolean} T - A boolean type. + * @template {boolean} U - A boolean type. * * @example * For example, we can use `Nimply` to determine whether two boolean types diff --git a/src/boolean/nor-all.spec.ts b/src/boolean/nor-all.spec.ts index 5a422ec5f..27faa0bc4 100644 --- a/src/boolean/nor-all.spec.ts +++ b/src/boolean/nor-all.spec.ts @@ -12,6 +12,10 @@ type NorAll_Spec = [ * An array of mixed booleans resolves to false */ Test.Expect<$, false>, + /** + * An array of all falses resolves to true + */ + Test.Expect<$, true>, /** * Running 'NorAll' on a non-boolean type should emit an error. */ diff --git a/src/boolean/nor-all.ts b/src/boolean/nor-all.ts index be4e4f5e7..705754a65 100644 --- a/src/boolean/nor-all.ts +++ b/src/boolean/nor-all.ts @@ -4,7 +4,7 @@ import { Kind, Type } from '..' * `_$norAll` is a type-level function that determines whether none of the * elements in a sequence of booleans are `true`. * - * @template B - A sequence of booleans. + * @template {boolean[]} B - A sequence of booleans. * * @example * For example, we can use `_$norAll` to check if none of the elements in a @@ -29,8 +29,10 @@ type FalseList< > = Output /** - * `NorAll` is a type-level function that applies the '_$norAll' operation to - * a sequence of booleans. + * `NorAll` is a type-level function that returns true only if every element in + * the given sequence of booleans is false. + * + * @template {boolean[]} B - A sequence of booleans. * * @example * For example, we can use `NorAll` to check if none of the elements in a @@ -42,7 +44,7 @@ type FalseList< * ```ts * import { $, Boolean } from "hkt-toolbelt"; * - * type Result = $<$>; // true + * type Result = $; // true * ``` */ export interface NorAll extends Kind.Kind { diff --git a/src/boolean/nor.ts b/src/boolean/nor.ts index 5e201ae85..1ca707a23 100644 --- a/src/boolean/nor.ts +++ b/src/boolean/nor.ts @@ -1,4 +1,4 @@ -import { Type, Kind } from '..' +import { Kind, Type } from '..' /** * `_$nor` is a type-level function that takes in two boolean types, `T` and @@ -6,8 +6,8 @@ import { Type, Kind } from '..' * on `T` and `U`. If both `T` and `U` are false, then `_$nor` returns true, * otherwise it returns false. * - * @template T - A boolean type. - * @template U - A boolean type. + * @template {boolean} T - A boolean type. + * @template {boolean} U - A boolean type. * * @example * For example, we can use `_$nor` to determine whether two boolean types are @@ -36,8 +36,8 @@ interface Nor_T extends Kind.Kind { * `U`, and returns the boolean result of applying the 'nor' logical operation * on `T` and `U`. * - * @template T - A boolean type. - * @template U - A boolean type. + * @template {boolean} T - A boolean type. + * @template {boolean} U - A boolean type. * * @example * For example, we can use `Nor` to determine whether two boolean types are both diff --git a/src/boolean/not.ts b/src/boolean/not.ts index f995c4282..3d9ebeccf 100644 --- a/src/boolean/not.ts +++ b/src/boolean/not.ts @@ -1,11 +1,11 @@ -import { Type, Kind } from '..' +import { Kind, Type } from '..' /** * `_$not` is a type-level function that takes in a boolean type `T`, and * returns the boolean result of applying the 'not' logical operation on `T`. * If `T` is true, then `_$not` returns false, otherwise it returns true. * - * @template T - A boolean type. + * @template {boolean} T - A boolean type. * * @example * For example, we can use `_$not` to negate a boolean type: @@ -22,7 +22,7 @@ export type _$not = T extends true ? false : true * `Not` is a type-level function that takes in a boolean type `T`, and * returns the boolean result of applying the 'not' logical operation on `T`. * - * @template T - A boolean type. + * @template {boolean} T - A boolean type. * * @example * For example, we can use `Not` to negate a boolean type: diff --git a/src/boolean/or-all.ts b/src/boolean/or-all.ts index a3237fcdb..d9386bd9d 100644 --- a/src/boolean/or-all.ts +++ b/src/boolean/or-all.ts @@ -5,7 +5,7 @@ import { _$norAll } from './nor-all' * `_$orAll` is a type-level function that determines whether any of the * elements in a sequence of booleans are `true`. * - * @template B - A sequence of booleans. + * @template {boolean[]} B - A sequence of booleans. * * @example * For example, we can use `_$orAll` to check if any of the elements in a @@ -25,8 +25,10 @@ export type _$orAll = 0 extends B['length'] : true /** - * `OrAll` is a type-level function that applies the '_$orAll' operation to - * a sequence of booleans. + * `OrAll` is a type-level function that returns true if any of the elements in + * the given sequence of booleans are true. + * + * @template {boolean[]} T - The boolean array to check. * * @example * For example, we can use `OrAll` to check if any of the elements in a @@ -38,7 +40,7 @@ export type _$orAll = 0 extends B['length'] * ```ts * import { $, Boolean } from "hkt-toolbelt"; * - * type Result = $<$>; // false + * type Result = $; // false * ``` */ export interface OrAll extends Kind.Kind { diff --git a/src/boolean/or.ts b/src/boolean/or.ts index f1e701588..95395f130 100644 --- a/src/boolean/or.ts +++ b/src/boolean/or.ts @@ -1,4 +1,4 @@ -import { Type, Kind } from '..' +import { Kind, Type } from '..' /** * `_$or` is a type-level function that takes in two boolean types, `T` and @@ -6,8 +6,8 @@ import { Type, Kind } from '..' * on `T` and `U`. If either `T` or `U` is true, then `_$or` returns true, * otherwise it returns false. * - * @template T - A boolean type. - * @template U - A boolean type. + * @template {boolean} T - A boolean type. + * @template {boolean} U - A boolean type. * * @example * For example, we can use `_$or` to determine whether at least one of two boolean @@ -36,8 +36,8 @@ interface Or_T extends Kind.Kind { * `U`, and returns the boolean result of applying the 'or' logical operation * on `T` and `U`. * - * @template T - A boolean type. - * @template U - A boolean type. + * @template {boolean} T - A boolean type. + * @template {boolean} U - A boolean type. * * @example * For example, we can use `Or` to determine whether at least one of two boolean diff --git a/src/boolean/xnor-all.ts b/src/boolean/xnor-all.ts index eec70f09e..f27ba6385 100644 --- a/src/boolean/xnor-all.ts +++ b/src/boolean/xnor-all.ts @@ -1,20 +1,20 @@ -import { Kind, NaturalNumber, Type, $ } from '..' +import { $, Kind, NaturalNumber, Type } from '..' /** - * `_$xnorAll` is a type-level function that determines whether an even number + * `_$xnorAll` is a type-level function that determines whether an odd number * of elements in a sequence of booleans are `true`. * - * @template B - A sequence of booleans. + * @template {boolean[]} B - A sequence of booleans. * * @example - * For example, we can use `_$xnorAll` to check if an even number of elements + * For example, we can use `_$xnorAll` to check if an odd number of elements * in a boolean array are `true`. In this example, we have an array with an odd * number of `true` elements: * * ```ts * import { Boolean } from "hkt-toolbelt"; * - * type Result = Boolean._$xnorAll<[true, false, true]>; // false + * type Result = Boolean._$xnorAll<[true, false, false]>; // false * ``` */ export type _$xnorAll = $< @@ -34,8 +34,10 @@ type NumberOfTrues< > = Output /** - * `XnorAll` is a type-level function that applies the '_$xnorAll' operation to - * a sequence of booleans. + * `XnorAll` is a type-level function that returns true if an odd number of + * elements in the given sequence of booleans are true. + * + * @template {boolean[]} T - The boolean array to check. * * @example * For example, we can use `XnorAll` to check if an even number of elements in @@ -47,7 +49,7 @@ type NumberOfTrues< * ```ts * import { $, Boolean } from "hkt-toolbelt"; * - * type Result = $<$>; // false + * type Result = $; // false * ``` */ export interface XnorAll extends Kind.Kind { diff --git a/src/boolean/xnor.ts b/src/boolean/xnor.ts index 3e4b876f5..88b1acf50 100644 --- a/src/boolean/xnor.ts +++ b/src/boolean/xnor.ts @@ -1,4 +1,4 @@ -import { Type, Kind } from '..' +import { Kind, Type } from '..' /** * `_$xnor` is a type-level function that takes in two boolean types, `T` and @@ -6,8 +6,8 @@ import { Type, Kind } from '..' * on `T` and `U`. If `T` and `U` are equal, then `_$xnor` returns true, * otherwise it returns false. * - * @template T - A boolean type. - * @template U - A boolean type. + * @template {boolean} T - A boolean type. + * @template {boolean} U - A boolean type. * * @example * For example, we can use `_$xnor` to determine whether two boolean types are @@ -43,8 +43,8 @@ interface Xnor_T extends Kind.Kind { * `U`, and returns the boolean result of applying the 'xnor' logical operation * on `T` and `U`. * - * @template T - A boolean type. - * @template U - A boolean type. + * @template {boolean} T - A boolean type. + * @template {boolean} U - A boolean type. * * @example * For example, we can use `Xnor` to determine whether two boolean types are diff --git a/src/boolean/xor.ts b/src/boolean/xor.ts index 591d8bc9c..a8cb18565 100644 --- a/src/boolean/xor.ts +++ b/src/boolean/xor.ts @@ -1,4 +1,4 @@ -import { Type, Kind } from '..' +import { Kind, Type } from '..' /** * `_$xor` is a type-level function that takes in two boolean types, `T` and @@ -6,8 +6,8 @@ import { Type, Kind } from '..' * logical operation on `T` and `U`. If `T` and `U` are the same, then * `_$xor` returns false, otherwise it returns true. * - * @template T - A boolean type. - * @template U - A boolean type. + * @template {boolean} T - A boolean type. + * @template {boolean}U - A boolean type. * * @example * For example, we can use `_$xor` to determine whether two boolean types are @@ -33,8 +33,8 @@ interface Xor_T extends Kind.Kind { * `U`, and returns the boolean result of applying the 'exclusive or' (xor) * logical operation on `T` and `U`. * - * @template T - A boolean type. - * @template U - A boolean type. + * @template {boolean} T - A boolean type. + * @template {boolean} U - A boolean type. * * @example * For example, we can use `Xor` to determine whether two boolean types are diff --git a/src/combinator/apply-self.ts b/src/combinator/apply-self.ts index 3a1669260..c395e7c21 100644 --- a/src/combinator/apply-self.ts +++ b/src/combinator/apply-self.ts @@ -1,4 +1,4 @@ -import { $, Type, Kind, Combinator } from '..' +import { $, Combinator, Kind, Type } from '..' /** * `ApplySelf` is a higher-order type-level function that takes in a recursive @@ -11,7 +11,7 @@ import { $, Type, Kind, Combinator } from '..' * where the function `f` takes in itself as an argument, and returns its own * application to itself. * - * @template F - A recursive kind that takes in itself as a type argument. + * @template {Kind} F - A recursive kind that takes in itself as a type argument. * * @example * For example, we can use `ApplySelf` to create the omega combinator, which diff --git a/src/combinator/collate.ts b/src/combinator/collate.ts index 93da3cc8f..5ccd327c0 100644 --- a/src/combinator/collate.ts +++ b/src/combinator/collate.ts @@ -1,4 +1,4 @@ -import { Kind, NaturalNumber, Number, Conditional, Type } from '..' +import { Conditional, Kind, NaturalNumber, Number, Type } from '..' interface _$collate2< /** @@ -43,7 +43,7 @@ export type _$collate = N extends 0 ? [] : _$collate2 * applications will return a tuple of length `N`, containing the arguments * applied. * - * @template N - The arity of the type-level function to create. + * @template {number} N - The arity of the type-level function to create. * * This is useful for creating type-level functions that are 'variadic' in the * sense that they can take in a specified number of arguments. diff --git a/src/combinator/fix-sequence.ts b/src/combinator/fix-sequence.ts index 47e828cfb..d3011f83c 100644 --- a/src/combinator/fix-sequence.ts +++ b/src/combinator/fix-sequence.ts @@ -1,4 +1,4 @@ -import { $, Type, Kind } from '..' +import { $, Kind, Type } from '..' /** * _$fixSequence is a type-level function that generates a fixed-point sequence @@ -122,6 +122,9 @@ interface FixSequence_T extends Kind.Kind { * next value in the sequence is the result of applying `KIND` to the previous * value, and so on, until the value reaches a fixed point. * + * @template {Kind} F - The kind for which the fixed-point sequence is generated. + * @template {InputOf} X - The initial value of the fixed-point sequence. + * * A fixed point is reached when applying `KIND` to a value returns that same * value. Notably, this means that an infinite loop is possible if we do not * converge to a fixed point. diff --git a/src/combinator/recursive-kind.ts b/src/combinator/recursive-kind.ts index 68cc6610f..5803e1e6e 100644 --- a/src/combinator/recursive-kind.ts +++ b/src/combinator/recursive-kind.ts @@ -1,10 +1,12 @@ -import { Type, Kind } from '..' +import { Kind, Type } from '..' /** * `RecursiveKind` is a higher-order type-level function that serves as a * subtype. It is used to express the fact that some other higher-order kind * takes in itself as a type argument. * + * @template {RecursiveKind} F - Input type of the recursive kind. + * * This type-level function doesn't do much on its own, but it is useful in * combination with other type-level functions. */ diff --git a/src/combinator/self.ts b/src/combinator/self.ts index a8c95c0bd..8f7fcd35d 100644 --- a/src/combinator/self.ts +++ b/src/combinator/self.ts @@ -4,6 +4,9 @@ import { Kind } from '..' * `Self` is a higher-order type-level function that outputs itself. Since it * outputs itself, it can be applied an arbitrary amount of times. * + * @template {any} X - An ignored input type. + * + * @example * ```ts * import { $, Combinator } from "hkt-toolbelt"; * diff --git a/src/conditional/equals-all.ts b/src/conditional/equals-all.ts index b2b551c16..5a270ccde 100644 --- a/src/conditional/equals-all.ts +++ b/src/conditional/equals-all.ts @@ -1,11 +1,10 @@ -import { Type, Kind, List, Conditional } from '..' +import { Conditional, Kind, List, Type } from '..' /** * `_$equalsAll` is a type-level function that takes in an array of types `T`, * and returns `true` if all elements of `T` are equal or `T` is empty. * - * @template T - An array of types. - * @template U - A type. + * @template {any[]} T - An array of types. * * @example * For example, we can use `_$equalsAll` to determine whether a series of types are equal. @@ -62,7 +61,7 @@ export type _$equalsAll = T extends [ * type-level function that returns `true` if all elements of `T` evaluate to the same type or `T` is empty, * and `false` if otherwise. * - * @template T - An array of types. + * @template {any[]} T - An array of types. * * @example * For example, we can use `EqualsAll` to determine whether multiple types are equal. diff --git a/src/conditional/equals.spec.ts b/src/conditional/equals.spec.ts index 30b9c0553..8f77c4f7b 100644 --- a/src/conditional/equals.spec.ts +++ b/src/conditional/equals.spec.ts @@ -64,3 +64,11 @@ type Equals_Spec = [ Test.Expect<$<$, Record>>, Test.Expect<$<$, [{}]>> ] + +it('should return true for equal values', () => { + expect(Conditional.equals(1)(1)).toBe(true) +}) + +it('should return false for unequal values', () => { + expect(Conditional.equals(1)(2)).toBe(false) +}) diff --git a/src/conditional/equals.ts b/src/conditional/equals.ts index 4afe428d9..ae004014a 100644 --- a/src/conditional/equals.ts +++ b/src/conditional/equals.ts @@ -4,8 +4,8 @@ import { Kind } from '..' * `_$equals` is a type-level function that takes in two types, `T` and `U`, and * returns `true` if `T` and `U` are the same type, and `false` otherwise. * - * @template T - A type. - * @template U - A type. + * @template {any} T - A type. + * @template {any} U - A type. * * @example * For example, we can use `_$equals` to determine whether two types are equal. @@ -39,8 +39,8 @@ interface Equals_T extends Kind.Kind { * type-level function that takes in one type, `U`, and returns `true` if `U` is * the same type as `T`, and `false` otherwise. * - * @template T - A type. - * @template U - A type. + * @template {any} T - A type. + * @template {any} U - A type. * * @example * For example, we can use `Equals` to determine whether two types are equal. @@ -60,3 +60,22 @@ interface Equals_T extends Kind.Kind { export interface Equals extends Kind.Kind { f(x: this[Kind._]): Equals_T } + +/** + * Given two values `x` and `y`, returns a function that returns `true` if `x` + * is equal to `y`, and `false` otherwise. + * + * @param {unknown} x - The first value to compare. + * @param {unknown} y - The second value to compare. + * + * `x => y => x === y` + * + * @example + * ```ts + * import { $, Conditional } from "hkt-toolbelt"; + * + * const result = Conditional.equals('foo')('foo') // true + * ``` + */ +export const equals = ((x: unknown) => (y: unknown) => + x === y) as Kind._$reify diff --git a/src/conditional/extends-all.ts b/src/conditional/extends-all.ts index 39c30d270..81dcd8ce3 100644 --- a/src/conditional/extends-all.ts +++ b/src/conditional/extends-all.ts @@ -1,12 +1,12 @@ -import { Type, Kind, List, Conditional } from '..' +import { Conditional, Kind, List, Type } from '..' /** * `_$extendsAll` is a type-level function that takes in an array of types `T` and a type `U`, * and returns `true` if and only if all elements of `T` extend `U`, or `T` is empty. * Otherwise it returns `false`. * - * @template T - An array of types. - * @template U - A type. + * @template {any[]} T - An array of types. + * @template {any} U - A type. * * @example * For example, we can use `_$extendsAll` to determine whether a series of type expressions all extend a second input type. @@ -68,8 +68,8 @@ interface ExtendsAll_T extends Kind.Kind { * * If T is empty, `true` is returned. * - * @template U - A type. - * @template T - An array of types. + * @template {any} U - A type. + * @template {any[]} T - An array of types. * * @example * For example, we can use `ExtendsAll` to determine whether a series of types all extend a second input type. @@ -86,5 +86,5 @@ interface ExtendsAll_T extends Kind.Kind { * ``` */ export interface ExtendsAll extends Kind.Kind { - f(x: Type._$cast): ExtendsAll_T + f(x: this[Kind._]): ExtendsAll_T } diff --git a/src/conditional/extends.ts b/src/conditional/extends.ts index 527375655..fa09e01ba 100644 --- a/src/conditional/extends.ts +++ b/src/conditional/extends.ts @@ -11,8 +11,8 @@ import { Kind } from '..' * ensures that we are only checking if `X` is a subtype of `T`, rather than * checking if `T` is a subtype of `X`. * - * @template T - The supertype that we are checking if `X` extends. - * @template X - The type that we are checking if it is a subtype of `T`. + * @template {any} T - The supertype that we are checking if `X` extends. + * @template {any} X - The type that we are checking if it is a subtype of `T`. * * @example * For example, we can use `_$extends` to determine whether a type is a subtype @@ -39,8 +39,8 @@ interface Extends_T extends Kind.Kind { * `Extends` is a type-level function that takes in two types, `T` and `U`, and * returns a boolean that represents whether `T` extends `U`. * - * @template T - The supertype that we are checking if `U` extends. - * @template U - The type that we are checking if it is a subtype of `T`. + * @template {any} T - The supertype that we are checking if `U` extends. + * @template {any} U - The type that we are checking if it is a subtype of `T`. * * @example * For example, we can use `Extends` to determine whether a type `T` extends a diff --git a/src/conditional/if.ts b/src/conditional/if.ts index 0194b5b6a..c5c232b56 100644 --- a/src/conditional/if.ts +++ b/src/conditional/if.ts @@ -1,4 +1,5 @@ -import { $, Type, Kind } from '..' +import { $, Kind, Type } from '..' +import { InputOf } from '../kind' /** * `_$if` is a type-level function that evaluates a predicate `Predicate` with @@ -55,12 +56,12 @@ interface If_T1 boolean>> * * This can be thought of as a type-level ternary operator. * - * @template Predicate - A type-level function of the form `(x: never) => boolean`. - * @template Then - A type-level function that is applied when the predicate returns + * @template {Kind} Predicate - A type-level function that returns a boolean. + * @template {Kind} Then - A type-level function that is applied when the predicate returns * `true`. - * @template Else - A type-level function that is applied when the predicate returns + * @template {Kind} Else - A type-level function that is applied when the predicate returns * `false`. - * @template X - The input to the predicate function. + * @template {InputOf} X - The input to the predicate function. * * ## Usage Examples * diff --git a/src/conditional/is-supertype-of.ts b/src/conditional/is-supertype-of.ts index e2e2d2136..4e1451273 100644 --- a/src/conditional/is-supertype-of.ts +++ b/src/conditional/is-supertype-of.ts @@ -12,8 +12,8 @@ import { $, $$, Conditional, Kind } from '..' * This is useful if it is known that `T` extends `X`, * but the two arguments are being supplied in the opposite order expected by `_$extends`. * - * @template T - The subtype that we are checking if `X` is a supertype of. - * @template X - The type that we are checking if it is a supertype of `T`. + * @template {any} T - The subtype that we are checking if `X` is a supertype of. + * @template {any} X - The type that we are checking if it is a supertype of `T`. * * @example * For example, we can use `_$isSupertypeOf` to determine whether a type is a supertype @@ -48,8 +48,8 @@ interface IsSupertypeOf_T extends Kind.Kind { * This is useful if it is known that `U` extends `T`, * but the two arguments are being supplied in the opposite order expected by `Extends`. * - * @template T - The supertype that we are checking if `U` extends. - * @template U - The type that we are checking if it is a subtype of `T`. + * @template {any} T - The supertype that we are checking if `U` extends. + * @template {any} U - The type that we are checking if it is a subtype of `T`. * * @example * For example, we can use `IsSupertypeOf` to determine whether a given type `T` is a supertype of @@ -64,6 +64,7 @@ interface IsSupertypeOf_T extends Kind.Kind { * type Result = $<$, boolean>; // true * ``` * + * @example * In the following examples, we test whether a number is a supertype of a string: * * ```ts diff --git a/src/conditional/not-equals.ts b/src/conditional/not-equals.ts index 14734d3e4..08e7379e7 100644 --- a/src/conditional/not-equals.ts +++ b/src/conditional/not-equals.ts @@ -4,8 +4,8 @@ import { Kind } from '..' * `_$notEquals` is a type-level function that returns `true` if `T` and `U` are * not equal. Otherwise, it returns `false`. * - * @template T - The first type to compare. - * @template U - The second type to compare. + * @template {any} T - The first type to compare. + * @template {any} U - The second type to compare. * * @example * In this example, `true` and `false` are passed as type arguments to the @@ -27,8 +27,8 @@ interface NotEquals_T extends Kind.Kind { * `NotEquals` is a type-level function that returns `true` if `T` and `U` are * not equal. Otherwise, it returns `false`. * - * @template T - The first type to compare. - * @template U - The second type to compare. + * @template {any} T - The first type to compare. + * @template {any} U - The second type to compare. * * @example * ```ts diff --git a/src/digit-list.ts b/src/digit-list.ts index 6eb41ba2e..7e4e4b0c6 100644 --- a/src/digit-list.ts +++ b/src/digit-list.ts @@ -9,7 +9,7 @@ export * from './digit-list/' * ```ts * import { $, DigitList } from 'hkt-toolbelt' * - * type Result = $<$, [4, 5, 6]> // [5, 7, 9] + * type Result = $<$, ["4", "5", "6"]> // ["5", "7", "9"] * ``` */ declare module './digit-list' {} diff --git a/src/digit-list/multiply-digit.ts b/src/digit-list/multiply-digit.ts index 19fa46d53..49b14c38a 100644 --- a/src/digit-list/multiply-digit.ts +++ b/src/digit-list/multiply-digit.ts @@ -1,4 +1,4 @@ -import { Kind, Type, Digit, DigitList } from '..' +import { Digit, DigitList, Kind, Type } from '..' type _$multiplyDigit2< A extends DigitList.DigitList, @@ -44,7 +44,7 @@ export type _$multiplyDigit< B extends Digit.Digit > = B extends '0' ? ['0'] : _$multiplyDigit2 -export interface MultiplyDigit_T extends Kind.Kind { +interface MultiplyDigit_T extends Kind.Kind { f( x: Type._$cast ): _$multiplyDigit diff --git a/src/digit-list/multiply.ts b/src/digit-list/multiply.ts index f1e67a212..b8fd201f8 100644 --- a/src/digit-list/multiply.ts +++ b/src/digit-list/multiply.ts @@ -1,4 +1,4 @@ -import { Type, Kind, Digit, DigitList } from '..' +import { Digit, DigitList, Kind, Type } from '..' /** * For each digit in the multiplicand, from right to left, we multiply the digit @@ -129,6 +129,7 @@ interface Multiply_T extends Kind.Kind { * * type IsZero = $<$, ["4", "2"]>; // ["0"] * type IsZero2 = $<$; // ["0"] + * ``` */ export interface Multiply extends Kind.Kind { f(x: Type._$cast): Multiply_T diff --git a/src/digit/add-tens.ts b/src/digit/add-tens.ts index 48d0a7ca4..8ef12cb0e 100644 --- a/src/digit/add-tens.ts +++ b/src/digit/add-tens.ts @@ -1,4 +1,4 @@ -import { Type, Digit, Kind } from '..' +import { Digit, Kind, Type } from '..' /** * `_addTens_LUT` is a type level lookup table for adding tens of two digits. @@ -23,8 +23,8 @@ type _$addTens_LUT = [ * the two specified digits. * Details can be found in the corresponding lookup-table `_$addTens_LUT`. * - * @template A - A one-character decimal digit type. - * @template B - A one-character decimal digit type. + * @template {Digit} A - A one-character decimal digit type. + * @template {Digit} B - A one-character decimal digit type. * * @example * For example, forwarding two decimal digits `5` and `6` will result in `1` @@ -49,9 +49,8 @@ interface AddTens_T extends Kind.Kind { * `AddTens` is a type-level function that takes two decimal digit types, * `A` and `B`, adds them together, and returns the resultant tens digit. * - * ## Parameters - * @template A - A one-character decimal digit type. - * @template B - A one-character decimal digit type. + * @template {Digit} A - A one-character decimal digit type. + * @template {Digit} B - A one-character decimal digit type. * * @example * For example, using the `hkt-toolbelt` `$` type-level applicator, diff --git a/src/digit/add.ts b/src/digit/add.ts index eb5f865e4..15666706a 100644 --- a/src/digit/add.ts +++ b/src/digit/add.ts @@ -1,4 +1,4 @@ -import { Type, Digit, Kind } from '..' +import { Digit, Kind, Type } from '..' /** * `_$add_LUT` is a type-level lookup table that contains the result of adding @@ -23,8 +23,8 @@ type _$add_LUT = [ * does not include any carry-over from the addition (see `_$addTens` for tens * place operation). * - * @template A - A one-character decimal digit type. - * @template B - A one-character decimal digit type. + * @template {Digit} A - A one-character decimal digit type. + * @template {Digit} B - A one-character decimal digit type. * * @example * For example, forwarding two decimal digits `7` and `4` will result in `1` @@ -50,9 +50,8 @@ interface Add_T extends Kind.Kind { * `A` and `B`, adds them together (excluding the carry-over), and returns * the resulting digit type. * - * ## Parameters - * @template A - A one-character decimal digit type. - * @template B - A one-character decimal digit type. + * @template {Digit} A - A one-character decimal digit type. + * @template {Digit} B - A one-character decimal digit type. * * @example * For example, using the `hkt-toolbelt` `$` type-level applicator, diff --git a/src/digit/compare.ts b/src/digit/compare.ts index e564b131e..019250748 100644 --- a/src/digit/compare.ts +++ b/src/digit/compare.ts @@ -27,8 +27,8 @@ type _$compare_LUT = [ * * It returns `1` if A > B, `-1` if A < B and `0` if A === B. * - * @template A - A one-character decimal digit type. - * @template B - A one-character decimal digit type. + * @template {Digit} A - A one-character decimal digit type. + * @template {Digit} B - A one-character decimal digit type. * * @example * For example, forwarding two decimal digits `7` and `4` will result in 1: @@ -54,12 +54,10 @@ interface Compare_T extends Kind.Kind { * and `B`, compares their magnitudes, and returns the corresponding result * {-1, 0, or 1}. * - * ## Parameters - * @template A - A one-character decimal digit type. - * @template B - A one-character decimal digit type. + * @template {Digit} A - A one-character decimal digit type. + * @template {Digit} B - A one-character decimal digit type. * * @example - * * For example, we can use the `$` type-level applicator to apply `Compare` to * two digits. In this example, we compare the digits `7` and `4`. * diff --git a/src/digit/decrement-tens.ts b/src/digit/decrement-tens.ts index 0da48fb2f..a80f4e373 100644 --- a/src/digit/decrement-tens.ts +++ b/src/digit/decrement-tens.ts @@ -1,4 +1,4 @@ -import { Type, Digit, Kind } from '..' +import { Digit, Kind, Type } from '..' /** * `_$decrementTens_LUT` is a type-level lookup table that maps decimal digits @@ -20,7 +20,7 @@ type _$decrementTens_LUT = ['1', '0', '0', '0', '0', '0', '0', '0', '0', '0'] * It only operates on individual digits and does not handle the logic * for the full subtraction or decrementing of the tens digit. * - * @template A - A one-character decimal digit type. + * @template {Digit} A - A one-character decimal digit type. * * @example * For example, forwarding a decimal digit `9` will result in: @@ -38,11 +38,9 @@ export type _$decrementTens = _$decrementTens_LUT[A] * type `A` and determines whether the tens digit should be decremented * during a subtraction operation. * - * ## Parameters - * @template A - A one-character decimal digit type. + * @template {Digit} A - A one-character decimal digit type. * * @example - * * For example, using the `hkt-toolbelt` `$` type-level applicator, we apply * `DecrementTens` to the digit `4`: * diff --git a/src/digit/decrement.ts b/src/digit/decrement.ts index 57932639f..c58122adb 100644 --- a/src/digit/decrement.ts +++ b/src/digit/decrement.ts @@ -1,4 +1,4 @@ -import { Type, Digit, Kind } from '..' +import { Digit, Kind, Type } from '..' /** * `_$decrement_LUT` is a type-level lookup table which maps each digit from "0" @@ -12,9 +12,7 @@ type _$decrement_LUT = ['9', '0', '1', '2', '3', '4', '5', '6', '7', '8'] * is immediately before the input digit in the sequence "0, 1, 2, 3, 4, 5, 6, * 7, 8, 9". * - * ## Parameter - * - * @template A - A single-digit type which represents a digit from "0" to "9". + * @template {Digit} A - A single-digit type which represents a digit from "0" to "9". * * @example * For example, if we want to subtract one from the digit "5", we would use @@ -35,7 +33,7 @@ export type _$decrement = _$decrement_LUT[A] * * We apply `Decrement` to a digit using the `$` type-level applicator. * - * @template A - A single-digit type which represents a digit from "0" to "9". + * @template {Digit} A - A single-digit type which represents a digit from "0" to "9". * * @example * For example, if we want to subtract one from the digit "5", we would use diff --git a/src/digit/digit.ts b/src/digit/digit.ts index 432fac32a..9e574f1c4 100644 --- a/src/digit/digit.ts +++ b/src/digit/digit.ts @@ -3,26 +3,5 @@ * from "0" to "9" (inclusive). Each decimal digit is represented as a string * literal type. This type is particularly useful when working with * type-level numerical operations or string manipulation involving numbers. - * - * @example - * Here are some usage examples of the `Digit` type: - * - * ```ts - * import { Digit } from 'hkt-toolbelt' - * - * type MyDigit = Digit // "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | - * "8" | "9" - * ``` - * - * @example - * You can also use the `Digit` type in combination with other `hkt-toolbelt` - * utilities such as numerical operations or string manipulation. - * - * ```ts - * import { Digit, String } from 'hkt-toolbelt' - * - * // `Increment` utility increments a decimal digit by 1. - * type One = $ // "1" - * ``` */ export type Digit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' diff --git a/src/digit/increment-tens.ts b/src/digit/increment-tens.ts index fe100087e..e8a38d41d 100644 --- a/src/digit/increment-tens.ts +++ b/src/digit/increment-tens.ts @@ -1,4 +1,4 @@ -import { Type, Digit, Kind } from '..' +import { Digit, Kind, Type } from '..' /** * `_$incrementTens_LUT` is a type-level lookup table that maps a digit type to @@ -13,7 +13,7 @@ type _$incrementTens_LUT = ['0', '0', '0', '0', '0', '0', '0', '0', '0', '1'] * is "9", it returns "1", otherwise, it returns "0". The result can be used for * incrementing a tens place in a number string. * - * @template A - A digit type. + * @template {Digit} A - A digit type. * * @example * For example, incrementing a digit "9" will result in the tens place increment @@ -39,7 +39,7 @@ export type _$incrementTens = _$incrementTens_LUT[A] * `IncrementTens` is a type-level function that takes a digit type `A` as * input and returns the tens place increment for that digit. * - * @template A - A digit type. + * @template {Digit} A - A digit type. * * @example * We apply `IncrementTens` to a digit using the `$` type-level applicator: diff --git a/src/digit/increment.ts b/src/digit/increment.ts index 9cbda5877..c44e91b4e 100644 --- a/src/digit/increment.ts +++ b/src/digit/increment.ts @@ -1,4 +1,4 @@ -import { Type, Digit, Kind } from '..' +import { Digit, Kind, Type } from '..' /** * `_$increment_LUT` is a lookup table for the `_$increment` type-level @@ -11,7 +11,7 @@ type _$increment_LUT = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0'] * returns the next digit in the sequence. If the input digit is "9", the * function returns "0". * - * @template A - A digit type. + * @template {Digit} A - A digit type. * * @example * For example, we can use `_$increment` to increment a digit type: @@ -29,7 +29,7 @@ export type _$increment = _$increment_LUT[A] * returns the next digit in the sequence. If the input digit is "9", the * function returns "0". * - * @template A - A digit type. + * @template {Digit} A - A digit type. * * @example * For example, we can use `Increment` to increment a digit type: diff --git a/src/digit/multiply-tens.ts b/src/digit/multiply-tens.ts index b8511538a..480e81f94 100644 --- a/src/digit/multiply-tens.ts +++ b/src/digit/multiply-tens.ts @@ -1,23 +1,5 @@ -import { Type, Kind, Digit } from '..' +import { Digit, Kind, Type } from '..' -/** - * `_$multiplyTens` is a type-level function that takes in two single-digit - * types, `A` and `B`, and returns the tens place of the product of `A` and `B`. - * This function works with digit types represented as strings. - * - * @template A - A single-digit type. - * @template B - A single-digit type. - * - * @example - * For example, we can use `_$multiplyTens` to compute the tens place of the - * product of two single-digit types: - * - * ```ts - * import { Digit } from "hkt-toolbelt" - * - * type Result = Digit._$multiplyTens<"5", "4"> // "2" - * ``` - */ type _$multiplyTens_LUT = [ ['0', '0', '0', '0', '0', '0', '0', '0', '0', '0'], ['0', '0', '0', '0', '0', '0', '0', '0', '0', '0'], @@ -36,8 +18,8 @@ type _$multiplyTens_LUT = [ * types, `A` and `B`, and returns the tens place of the product of `A` and `B`. * This function works with digit types represented as strings. * - * @template A - A single-digit type - * @template B - A single-digit type + * @template {Digit} A - A single-digit type + * @template {Digit} B - A single-digit type * * @example * ```ts @@ -59,8 +41,8 @@ interface MultiplyTens_T extends Kind.Kind { * `MultiplyTens` is a type-level function that takes in two single-digit * types, `A` and `B`, and returns the tens place of the product of `A` and `B`. * - * @template A - A single-digit type. - * @template B - A single-digit type. + * @template {Digit} A - A single-digit type. + * @template {Digit} B - A single-digit type. * * @example * For example, we can use `MultiplyTens` to compute the tens place of the diff --git a/src/digit/multiply.ts b/src/digit/multiply.ts index 21e319a05..87d621de3 100644 --- a/src/digit/multiply.ts +++ b/src/digit/multiply.ts @@ -1,4 +1,4 @@ -import { Type, Kind, Digit } from '..' +import { Digit, Kind, Type } from '..' /** * `_$multiply_LUT` is a type-level lookup table that is used by `_$multiply` to @@ -26,8 +26,8 @@ type _$multiply_LUT = [ * `B`, and returns the result of multiplying `A` by `B`, modulo 10. The result * is a single digit type. * - * @template A - A digit type. - * @template B - A digit type. + * @template {Digit} A - A digit type, the multiplier. + * @template {Digit} B - A digit type, the multiplicand. * * @example * For example, we can use `_$multiply` to multiply two digit types. In this @@ -53,8 +53,8 @@ interface Multiply_T extends Kind.Kind { * `B`, and returns the result of multiplying `A` by `B`, modulo 10. The result * is a single digit type. * - * @template A - A digit type. - * @template B - A digit type. + * @template {Digit} A - A digit type, the multiplier. + * @template {Digit} B - A digit type, the multiplicand. * * @example * For example, we can use `Multiply` to multiply two digit types. In this diff --git a/src/digit/subtract-tens.ts b/src/digit/subtract-tens.ts index a9c680b4a..a7741963e 100644 --- a/src/digit/subtract-tens.ts +++ b/src/digit/subtract-tens.ts @@ -1,4 +1,4 @@ -import { Type, Digit, Kind } from '..' +import { Digit, Kind, Type } from '..' /** * `_$subtractTens_LUT` is a lookup table used internally by `_$subtractTens` @@ -22,8 +22,8 @@ type _$subtractTens_LUT = [ * and `B`, and returns the result of subtracting `B` from `A` in the tens * place. If `B` is greater than `A`, the result is 1. * - * @template A - A digit type. - * @template B - A digit type. + * @template {Digit} A - A digit type, the minuend. + * @template {Digit} B - A digit type, the subtrahend. * * @example * For example, we can use `_$subtractTens` to subtract two digit types in the @@ -53,8 +53,8 @@ interface SubtractTens_T extends Kind.Kind { * and `B`, and returns the result of subtracting `B` from `A` in the tens * place. If `B` is greater than `A`, the result is 1. * - * @template A - A digit type. - * @template B - A digit type. + * @template {Digit} A - A digit type, the minuend. + * @template {Digit} B - A digit type, the subtrahend. * * @example * For example, we can use `SubtractTens` to subtract two digit types in the diff --git a/src/digit/subtract.ts b/src/digit/subtract.ts index e0512773c..9fe3b43f1 100644 --- a/src/digit/subtract.ts +++ b/src/digit/subtract.ts @@ -1,4 +1,4 @@ -import { Type, Digit, Kind } from '..' +import { Digit, Kind, Type } from '..' /** * `_$subtract_LUT` is a lookup table that contains the results of all possible @@ -28,8 +28,8 @@ type _$subtract_LUT = [ * subtraction is performed using a lookup table (`_$subtract_LUT`), which * contains the results of all possible digit subtractions. * - * @template A - A digit type. - * @template B - A digit type. + * @template {Digit} A - A digit type, the minuend. + * @template {Digit} B - A digit type, the subtrahend. * * @example * For example, we can use `_$subtract` to subtract two digit types. In this @@ -54,8 +54,8 @@ interface Subtract_T extends Kind.Kind { * `Subtract` is a type-level function that takes in two digit types, `A` and * `B`, and returns the digit result of subtracting `B` from `A`. * - * @template A - A digit type. - * @template B - A digit type. + * @template {Digit} A - A digit type, the minuend. + * @template {Digit} B - A digit type, the subtrahend. * * @example * For example, we can use `Subtract` to subtract two digit types. In this diff --git a/src/function/constant.ts b/src/function/constant.ts index 46a6a791a..328c41d04 100644 --- a/src/function/constant.ts +++ b/src/function/constant.ts @@ -5,13 +5,10 @@ interface Constant_T extends Kind.Kind { } /** - * `Constant` is a type-level function that returns a constant value regardless - * of its input. - * - * It ignores its argument and always returns the configured constant value. + * `Constant` is a type-level function that constructs a type-level function + * which always returns the given value, regardless of input. * * @template T - The constant value to return. - * @template X - The input type. This is ignored. * * @returns The configured constant value T. * diff --git a/src/function/identity.ts b/src/function/identity.ts index 3539b84ff..24fb4da37 100644 --- a/src/function/identity.ts +++ b/src/function/identity.ts @@ -6,7 +6,7 @@ import { Kind } from '..' * It acts as the "identity" function at the type level. * * @template T - The input type to return unchanged - * @template x - The input value of type T + * * @returns The input value x, unchanged * * @example diff --git a/src/kind/apply-n.ts b/src/kind/apply-n.ts index 9aee5a634..b475e3ae1 100644 --- a/src/kind/apply-n.ts +++ b/src/kind/apply-n.ts @@ -1,4 +1,4 @@ -import { Type, Kind } from '..' +import { Kind, Type } from '..' interface ApplyN_T extends Kind.Kind { f(x: Type._$cast): Kind._$uncurry @@ -11,6 +11,7 @@ interface ApplyN_T extends Kind.Kind { * K to X using the `$N` operator. * * @see {@link Kind.Uncurry} + * * `ApplyN` is `Kind.Uncurry` with the argument positions reversed. * Here, we first take in the values, and then a kind to apply to those values. * diff --git a/src/kind/apply.ts b/src/kind/apply.ts index 775a01823..97c6d580d 100644 --- a/src/kind/apply.ts +++ b/src/kind/apply.ts @@ -1,4 +1,4 @@ -import { $, Type, Kind } from '..' +import { $, Kind, Type } from '..' /** * `_$apply` is the internal implementation for the `Apply` utility. @@ -30,7 +30,7 @@ interface Apply_T extends Kind.Kind { * K to the casted X using the `$` operator. * * @see {@link $} - * Notably, the argument positions are reversed compared to `$`. + * Notably, the argument positions are reversed compared to `\$`. * Here, we first take in a value, and then a kind to apply to that value. * * @template X - The value of type X to apply the kind to diff --git a/src/kind/arity.ts b/src/kind/arity.ts index 3edc1fb2c..cf987c93d 100644 --- a/src/kind/arity.ts +++ b/src/kind/arity.ts @@ -1,4 +1,4 @@ -import { $, Kind, Type, Number, NaturalNumber } from '..' +import { $, Kind, NaturalNumber, Number, Type } from '..' /** * `_$arity` is a type-level function that takes in a curried type-level function, @@ -28,10 +28,12 @@ export type _$arity = * If `K` is not a `Kind`, an error will be emitted. * * @example + * ```ts * type ReduceArity = $ // 3 * type PartialApply1 = $> // 2 * type PartialApply2 = $, never>> // 1 * type FullApply = $, never>, never>> // 0 + * ``` */ export interface Arity extends Kind.Kind { f(x: Type._$cast): _$arity diff --git a/src/kind/composable-pair.ts b/src/kind/composable-pair.ts index f2512cf12..5b4f1cd82 100644 --- a/src/kind/composable-pair.ts +++ b/src/kind/composable-pair.ts @@ -1,4 +1,4 @@ -import { Type, Kind } from '..' +import { Kind, Type } from '..' /** * `_$composablePair` is the internal implementation for the `ComposablePair` @@ -11,6 +11,9 @@ import { Type, Kind } from '..' * composed with g, and we say that 'g is piped into f'. In other words, * composition is a right-to-left description. * + * If the output type of B is unknown, then we can't determine if A can be + * composed with B. In this case, we optimistically return true. + * * @template F - A tuple containing two kinds to check * * @returns Whether the kinds are composable @@ -24,8 +27,14 @@ import { Type, Kind } from '..' * Kind._$composablePair<[String.ToUpper, List.Reverse]> * ``` */ -export type _$composablePair = - Kind._$outputOf extends Kind._$inputOf ? true : false +export type _$composablePair< + F extends [Kind.Kind, Kind.Kind], + OUTPUT_OF = Kind._$outputOf +> = unknown extends OUTPUT_OF + ? true + : OUTPUT_OF extends Kind._$inputOf + ? true + : false /** * `ComposablePair` checks if two kinds can be composed together. diff --git a/src/kind/input-of.spec.ts b/src/kind/input-of.spec.ts index b509601ae..2372a01e8 100644 --- a/src/kind/input-of.spec.ts +++ b/src/kind/input-of.spec.ts @@ -1,4 +1,4 @@ -import { $, Kind, Number, NaturalNumber, List, Test } from '..' +import { $, Kind, List, NaturalNumber, Number, String, Test } from '..' type Add2 = $ type ReduceAdd = $ @@ -9,5 +9,10 @@ type InputOf_Spec = [ Test.Expect<$, unknown>, - Test.Expect<$, unknown[]> + Test.Expect<$, unknown[]>, + + /** + * Commutative with respect to unions. + */ + Test.Expect<$, Number.Number | string> ] diff --git a/src/object/at.ts b/src/object/at.ts index 4f9c74b91..2262932cb 100644 --- a/src/object/at.ts +++ b/src/object/at.ts @@ -1,5 +1,16 @@ import { Kind, Type } from '..' +/** + * `_$at` is a type-level function that returns the value at a given key in an object. + * + * @template K - The key to get the value of. + * @template T - The object to get the value from. + * @returns The value at the given key in the object. + * + * @example + * type T0 = Object._$at<'a', { a: 1; b: 2; c: 3 }> // 1 + * type T1 = Object._$at<'b', { a: 1; b: 2; c: 3 }> // 2 + */ export type _$at< K extends keyof T, T extends Record @@ -9,6 +20,16 @@ interface At_T extends Kind.Kind { f(x: Type._$cast>): _$at } +/** + * `At` is a type-level function that returns the value at a given key in an object. + * + * @template K - The key to get the value of. + * @returns The value at the given key in the object. + * + * @example + * type T0 = $<$, { a: 1; b: 2; c: 3 }> // 1 + * type T1 = $<$, { a: 1; b: 2; c: 3 }> // 2 + */ export interface At extends Kind.Kind { f(x: Type._$cast): At_T } diff --git a/src/object/map-keys.ts b/src/object/map-keys.ts index fde9aa374..16661c839 100644 --- a/src/object/map-keys.ts +++ b/src/object/map-keys.ts @@ -1,4 +1,4 @@ -import { $, Kind, Type, String } from '..' +import { $, Kind, Type } from '..' export type _$mapKeys< T extends Record, @@ -23,11 +23,3 @@ export interface MapKeys extends Kind.Kind { > ): MapKeys_T } - -declare const mapKeys: Kind._$reify - -declare const prepend: Kind._$reify - -const result = mapKeys(prepend('on_'))({ a: 1, b: 2, c: 3 }) - -type result = typeof result From 4fa388554f54e9676a446976c1761e10f7293307 Mon Sep 17 00:00:00 2001 From: poteat Date: Mon, 23 Sep 2024 18:34:18 -0700 Subject: [PATCH 06/17] feat: implement kind utilities --- package.json | 2 +- src/kind/juxt.spec.ts | 35 ++++++++++++++++++ src/kind/juxt.ts | 69 ++++++++++++++++++++++++++++++++++ src/kind/pipe-weak.spec.ts | 14 +++++++ src/kind/pipe-weak.ts | 76 ++++++++++++++++++++++++++++++++++++++ src/kind/pipe.spec.ts | 10 ++++- src/kind/pipe.ts | 26 +++++++++++-- src/kind/uncurry.ts | 4 +- 8 files changed, 229 insertions(+), 7 deletions(-) create mode 100644 src/kind/juxt.spec.ts create mode 100644 src/kind/juxt.ts create mode 100644 src/kind/pipe-weak.spec.ts create mode 100644 src/kind/pipe-weak.ts diff --git a/package.json b/package.json index 3ec52adf5..3ae2deb26 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "hkt-toolbelt", "private": true, "scripts": { - "test": "NODE_OPTIONS=--max-old-space-size=8192 tsc --project tsconfig.spec.json && jest", + "test": "NODE_OPTIONS=--max-old-space-size=8192 tsc --project tsconfig.spec.json", "stress": "NODE_OPTIONS=--max-old-space-size=24576 tsc --project tsconfig.stress.json", "build": "./build.sh", "build:docs": "typedoc --skipErrorChecking", diff --git a/src/kind/juxt.spec.ts b/src/kind/juxt.spec.ts new file mode 100644 index 000000000..2d90d2c4e --- /dev/null +++ b/src/kind/juxt.spec.ts @@ -0,0 +1,35 @@ +import { $, Kind, List, Test } from '..' + +type Juxt_Spec = [ + /** + * Apply `Juxt` with list operations. + */ + Test.Expect< + $<$, [1, 2, 3]>, + [3, [3, 2, 1]] + >, + + /** + * Apply `Juxt` with different kind operations. + */ + Test.Expect< + $<$, ['a', 'b', 'c']>, + ['a', 'c'] + >, + + /** + * Juxt with single operation returns a single-element tuple. + */ + Test.Expect<$<$, [1, 2, 3]>, [3]>, + + /** + * Juxt with incompatible kind results in type error. + */ + // @ts-expect-error + $<$, string>, + + /** + * A juxt of zero elements results in an empty tuple. + */ + Test.Expect<$<$, [1, 2, 3]>, []> +] diff --git a/src/kind/juxt.ts b/src/kind/juxt.ts new file mode 100644 index 000000000..c3b182eab --- /dev/null +++ b/src/kind/juxt.ts @@ -0,0 +1,69 @@ +import { $, Kind, Type } from '..' + +/** + * `_$juxt` is a type-level function that takes in a tuple of kinds `FX` and + * applies each kind in the tuple to the input type `X`. + * + * @template FX - A tuple of kinds to apply. + * @template X - The input type to apply the kinds to. + * + * @returns A tuple of the results of applying each kind in the tuple to `X`. + * + * @example + * + * In the below example, we apply `Kind._$juxt` to a tuple of two kinds, + * List.Length and List.Reverse. On the successive line, we apply the kinds to + * the input type `[1, 2, 3]`. The result is a tuple of two types, the first + * being the length of the input list `[1, 2, 3]` (3), and the second being the + * reversed list `[3, 2, 1]`. + * + * ```ts + * import { $, Kind, List } from "hkt-toolbelt"; + * + * type MyJuxt = Kind._$juxt<[List.Length, List.Reverse]>; + * + * type Result = $; // [3, [3, 2, 1]] + * ``` + */ +export type _$juxt = { + [key in keyof FX]: $>> +} + +interface Juxt_T extends Kind.Kind { + f( + x: Type._$cast< + this[Kind._], + FX extends [] ? unknown : Kind._$inputOf + > + ): _$juxt +} + +/** + * `Juxt` is a type-level function that applies a tuple of kinds to a type. + * + * This is useful for implementing point-free style type-level functions. + * + * @template FX - A tuple of kinds to apply. + * @template X - The input type to apply the kinds to. + * + * @returns A tuple of the results of applying each kind in the tuple to `X`. + * + * @example + * + * In the below example, we apply `Kind.Juxt` to a tuple of two kinds, + * List.Length and List.Reverse. On the successive line, we apply the kinds to + * the input type `[1, 2, 3]`. The result is a tuple of two types, the first + * being the length of the input list `[1, 2, 3]` (3), and the second being the + * reversed list `[3, 2, 1]`. + * + * ```ts + * import { $, Kind, List } from "hkt-toolbelt"; + * + * type MyJuxt = $; + * + * type Result = MyJuxt<[1, 2, 3]>; // [3, [3, 2, 1]] + * ``` + */ +export interface Juxt extends Kind.Kind { + f(x: Type._$cast): Juxt_T +} diff --git a/src/kind/pipe-weak.spec.ts b/src/kind/pipe-weak.spec.ts new file mode 100644 index 000000000..eda05c0ad --- /dev/null +++ b/src/kind/pipe-weak.spec.ts @@ -0,0 +1,14 @@ +import { $, Kind, String, Test } from '..' + +type PipeWeak_Spec = [ + /** + * Can pipe simple operations. + */ + Test.Expect< + $< + $, $]>, + 'baz' + >, + 'bazfoobar' + > +] diff --git a/src/kind/pipe-weak.ts b/src/kind/pipe-weak.ts new file mode 100644 index 000000000..bd393fed1 --- /dev/null +++ b/src/kind/pipe-weak.ts @@ -0,0 +1,76 @@ +import { Kind, List, Type } from '..' + +/** + * `PipeWeak` is a type-level function that takes a tuple of type-level + * functions and composes them from left to right, such that the output of the + * first function is the input of the second function, and so on. + * + * This is a weaker version of `Pipe` that does not enforce subtype + * constraints between the input and output of each function. + * + * The type constraint associated with the overall input, and the constraint + * enforcing a tuple of kinds are both still enforced. + * + * This is useful for pipes which are too complicated for the inputs and outputs + * to be correctly inferred. + * + * @template FX - A tuple of type-level functions that will be piped together. + * @template X - The type that the type-level functions will be applied to. + * + * @example + * + * ```ts + * import { $, Kind, String } from "hkt-toolbelt"; + * + * type MyFunc = $, + * $, + * ]> + * + * type Result = $ // "bazfoobar" + * ``` + */ +export type _$pipeWeak = Kind._$pipe + +interface PipeWeak_T extends Kind.Kind { + f( + x: Type._$cast< + this[Kind._], + FX extends [] ? unknown : Kind._$inputOf> + > + ): _$pipeWeak +} + +/** + * `PipeWeak` is a type-level function that takes a tuple of type-level + * functions and composes them from left to right, such that the output of the + * first function is the input of the second function, and so on. + * + * This is a weaker version of `Pipe` that does not enforce subtype + * constraints between the input and output of each function. + * + * The type constraint associated with the overall input, and the constraint + * enforcing a tuple of kinds are both still enforced. + * + * This is useful for pipes which are too complicated for the inputs and outputs + * to be correctly inferred. + * + * @template FX - A tuple of type-level functions that will be piped together. + * @template X - The type that the type-level functions will be applied to. + * + * @example + * + * ```ts + * import { $, Kind, String } from "hkt-toolbelt"; + * + * type MyFunc = $, + * $, + * ]> + * + * type Result = $ // "bazfoobar" + * ``` + */ +export interface PipeWeak extends Kind.Kind { + f(x: Type._$cast): PipeWeak_T +} diff --git a/src/kind/pipe.spec.ts b/src/kind/pipe.spec.ts index dc46f45f4..8ddbc0112 100644 --- a/src/kind/pipe.spec.ts +++ b/src/kind/pipe.spec.ts @@ -1,4 +1,4 @@ -import { $, Function, Kind, List, String, Test } from '..' +import { $, Function, Kind, List, NaturalNumber, String, Test } from '..' type Pipe_Spec = [ /** @@ -91,3 +91,11 @@ type Pipe_Spec = [ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] > ] + +it('should pipe functions together', () => { + const result = Kind.pipe([NaturalNumber.increment, NaturalNumber.increment])( + 0 + ) + + expect(result).toBe(2) +}) diff --git a/src/kind/pipe.ts b/src/kind/pipe.ts index ba338486a..5227971b1 100644 --- a/src/kind/pipe.ts +++ b/src/kind/pipe.ts @@ -1,4 +1,4 @@ -import { Type, List, Kind, NaturalNumber, $ } from '..' +import { Function, Kind, List, Type } from '..' /** * `_$pipe` is a type-level function that allows users to compose @@ -80,6 +80,26 @@ export interface Pipe extends Kind.Kind { : never } -type Foo = $ +/** + * Given a list of functions, pipe the functions together, applying them in + * order from left to right. + * + * @example + * ```ts + * import { Kind, NaturalNumber } from "hkt-toolbelt"; + * + * const result = Kind.pipe([ + * NaturalNumber.increment, + * NaturalNumber.increment + * ])(0) // 2 + * ``` + */ +export const pipe = ((fx: Function.Function[]) => (input: unknown) => { + let value = input + + for (const f of fx) { + value = f(value as never) + } -type Bar = $<$, 2> + return value +}) as Kind._$reify diff --git a/src/kind/uncurry.ts b/src/kind/uncurry.ts index c44596845..8ef7417f7 100644 --- a/src/kind/uncurry.ts +++ b/src/kind/uncurry.ts @@ -2,8 +2,8 @@ import { $, Kind, Type } from '..' /** * `_$uncurry` is a type-level function that takes in a type-level function and - * a list of arguments, and applies the type-level function to the list of - * arguments. + * a list of arguments, and applies each element of the list to the kind one-by- + * one. * * This is syntactic sugar for nested `$` applications. See `$N`, which is the * operator shorthand for this function. From 0b42799291b4fbd881f9f9a7b416e2b70c67ba8a Mon Sep 17 00:00:00 2001 From: poteat Date: Tue, 24 Sep 2024 13:33:27 -0700 Subject: [PATCH 07/17] feat: add various kind utilities --- src/kind/index.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/kind/index.ts b/src/kind/index.ts index 55d26f2c8..4bcef69aa 100644 --- a/src/kind/index.ts +++ b/src/kind/index.ts @@ -1,15 +1,17 @@ export * from './apply' export * from './apply-n' export * from './arity' -export * from './composable-pair' export * from './composable' +export * from './composable-pair' export * from './compose' export * from './curry' export * from './input-of' +export * from './juxt' export * from './kind' export * from './output-of' export * from './parameters' export * from './pipe' +export * from './pipe-weak' export * from './reify' export * from './unapply' export * from './uncurry' From 5dec3e504e4bbb6ccbc9e300f5ce19c448ad55cb Mon Sep 17 00:00:00 2001 From: poteat Date: Tue, 24 Sep 2024 13:33:44 -0700 Subject: [PATCH 08/17] feat: add various list utilities --- src/list/chunk.spec.ts | 28 ++++++++++++ src/list/chunk.ts | 70 +++++++++++++++++++++++++++++ src/list/duplicates.spec.ts | 38 ++++++++++++++++ src/list/duplicates.ts | 80 ++++++++++++++++++++++++++++++++++ src/list/flat-map.spec.ts | 21 +++++++++ src/list/flat-map.ts | 65 +++++++++++++++++++++++++++ src/list/includes.spec.ts | 45 ++++--------------- src/list/includes.ts | 36 ++++++++------- src/list/includesValue.spec.ts | 18 ++++++++ src/list/includesValue.ts | 51 ++++++++++++++++++++++ src/list/index.ts | 16 +++++-- src/list/intersect.spec.ts | 23 ++++++++++ src/list/intersect.ts | 59 +++++++++++++++++++++++++ src/list/length.spec.ts | 4 ++ src/list/length.ts | 14 +++++- src/list/map.spec.ts | 2 +- src/list/pushValue.spec.ts | 22 ++++++++++ src/list/pushValue.ts | 39 +++++++++++++++++ src/list/remove.spec.ts | 34 +++++++++++++++ src/list/remove.ts | 54 +++++++++++++++++++++++ src/list/repeat.spec.ts | 16 +++---- src/list/repeat.stress.spec.ts | 6 +-- src/list/repeat.ts | 40 +++++------------ src/list/unique.ts | 41 +++++++++++++++++ 24 files changed, 720 insertions(+), 102 deletions(-) create mode 100644 src/list/chunk.spec.ts create mode 100644 src/list/chunk.ts create mode 100644 src/list/duplicates.spec.ts create mode 100644 src/list/duplicates.ts create mode 100644 src/list/flat-map.spec.ts create mode 100644 src/list/flat-map.ts create mode 100644 src/list/includesValue.spec.ts create mode 100644 src/list/includesValue.ts create mode 100644 src/list/intersect.spec.ts create mode 100644 src/list/intersect.ts create mode 100644 src/list/pushValue.spec.ts create mode 100644 src/list/pushValue.ts create mode 100644 src/list/remove.spec.ts create mode 100644 src/list/remove.ts create mode 100644 src/list/unique.ts diff --git a/src/list/chunk.spec.ts b/src/list/chunk.spec.ts new file mode 100644 index 000000000..723247d5f --- /dev/null +++ b/src/list/chunk.spec.ts @@ -0,0 +1,28 @@ +import { $, List, Test } from '..' + +type Chunk_Spec = [ + /** + * Can chunk a list into sublists of a specified size. + */ + Test.Expect<$<$, [1, 2, 3, 4, 5]>, [[1, 2], [3, 4], [5]]>, + + /** + * Can chunk a list into length-3 sublists. + */ + Test.Expect<$<$, [1, 2, 3, 4, 5, 6]>, [[1, 2, 3], [4, 5, 6]]>, + + /** + * Trailing elements have a shorter sublist length. + */ + Test.Expect<$<$, [1, 2, 3, 4, 5]>, [[1, 2], [3, 4], [5]]>, + + /** + * Can handle an empty list. + */ + Test.Expect<$<$, []>, []>, + + /** + * Chunking by 0 results in the original list. + */ + Test.Expect<$<$, [1, 2, 3, 4, 5]>, [[1, 2, 3, 4, 5]]> +] diff --git a/src/list/chunk.ts b/src/list/chunk.ts new file mode 100644 index 000000000..a0fdeef45 --- /dev/null +++ b/src/list/chunk.ts @@ -0,0 +1,70 @@ +import { Kind, NaturalNumber, Type } from '..' + +/** + * `_$chunk` is a type-level function that takes in a number `N` and a list `T`, + * and returns a list of lists, where each sublist has a length of `N`. + * + * Trailing elements have a shorter sublist length. + * + * @template N - The length of each sublist. + * @template T - The list to chunk. + * @returns A list of lists, where each sublist has a length of `N`. + * + * @example + * For example, we can use `_$chunk` to chunk a list into sublists of length `N`: + * + * ```ts + * import { List } from "hkt-toolbelt"; + * + * type Result = List._$chunk<2, [1, 2, 3, 4, 5]>; // [[1, 2], [3, 4], [5]] + * ``` + */ +export type _$chunk< + N extends number, + T extends unknown[], + O extends unknown[][] = [], + IDX extends number = 1 +> = 0 extends 1 + ? never + : T extends [infer Head, ...infer Tail] + ? IDX extends N + ? _$chunk + : O extends [ + ...infer Init extends unknown[][], + infer Last extends unknown[] + ] + ? _$chunk< + N, + Tail, + [...Init, [...Last, Head]], + NaturalNumber._$increment + > + : _$chunk + : O + +interface Chunk_T extends Kind.Kind { + f(x: Type._$cast): _$chunk +} + +/** + * `Chunk` is a type-level function that takes in a number `N` and a list `T`, + * and returns a list of lists, where each sublist has a length of `N`. + * + * Trailing elements have a shorter sublist length. + * + * @template N - The length of each sublist. + * @template T - The list to chunk. + * @returns A list of lists, where each sublist has a length of `N`. + * + * @example + * For example, we can use `Chunk` to chunk a list into sublists of length `N`: + * + * ```ts + * import { $, List } from "hkt-toolbelt"; + * + * type Result = $<$, [1, 2, 3, 4, 5]>; // [[1, 2], [3, 4], [5]] + * ``` + */ +export interface Chunk extends Kind.Kind { + f(x: Type._$cast): Chunk_T +} diff --git a/src/list/duplicates.spec.ts b/src/list/duplicates.spec.ts new file mode 100644 index 000000000..ce045ad3c --- /dev/null +++ b/src/list/duplicates.spec.ts @@ -0,0 +1,38 @@ +import { $, List, Test } from '..' + +type Duplicates_Spec = [ + /** + * Can find the duplicates in a list. + */ + Test.Expect<$, [1]>, + + /** + * Can handle multiple duplicates. + */ + Test.Expect< + $, + [1, 2, 3, 4, 5] + >, + + /** + * Can find the duplicates in a list, even if the list is empty. + */ + Test.Expect<$, []>, + + /** + * All unique array results in an empty list. + */ + Test.Expect<$, []> +] + +it('should return the duplicates of a list', () => { + expect(List.duplicates([1, 2, 3, 4, 5, 1])).toEqual([1]) +}) + +it('should return an empty list if the input is empty', () => { + expect(List.duplicates([])).toEqual([]) +}) + +it('should return an empty list if the input is unique', () => { + expect(List.duplicates([1, 2, 3])).toEqual([]) +}) diff --git a/src/list/duplicates.ts b/src/list/duplicates.ts new file mode 100644 index 000000000..8960b2c0d --- /dev/null +++ b/src/list/duplicates.ts @@ -0,0 +1,80 @@ +import { Kind, List, Type } from '..' + +/** + * `_$duplicates` is a type-level function that takes in a list `T` and returns + * a list of the duplicate elements in `T`, i.e. those elements that appear + * more than once in `T`. + * + * Elements are ordered in the same order as the input list. Only the first + * occurrence of each element is included in the output list. + * + * @template T - The list to check. + * + * @example + * For example, we can use `_$duplicates` to find the duplicates in a list: + * + * ```ts + * import { List } from "hkt-toolbelt"; + * + * type Result = List._$duplicates<[1, 2, 3, 4, 5, 1]>; // [1] + * ``` + */ +export type _$duplicates< + T extends unknown[], + O extends unknown[] = [] +> = 0 extends 1 + ? never + : T extends [infer Head, ...infer Tail] + ? List._$includes extends true + ? List._$includes extends true + ? _$duplicates + : _$duplicates + : _$duplicates + : O + +/** + * `Duplicates` is a type-level function that takes in a list `T` and returns + * a list of the duplicate elements in `T`, i.e. those elements that appear + * more than once in `T`. + * + * Elements are ordered in the same order as the input list. Only the first + * occurrence of each element is included in the output list. + * + * @template T - The list to check. + * + * @example + * For example, we can use `Duplicates` to find the duplicates in a list: + * + * ```ts + * import { $, List } from "hkt-toolbelt"; + * + * type Result = $<$>; // [1] + * ``` + */ +export interface Duplicates extends Kind.Kind { + f(x: Type._$cast): _$duplicates +} + +/** + * Given a list, return a new list containing only the duplicate elements. + * + * @example + * ```ts + * import { List } from "hkt-toolbelt"; + * + * const result = List.duplicates([1, 2, 3, 4, 5, 1]) // [1] + * ``` + */ +export const duplicates = ((x: unknown[]) => { + const seen = new Set() + const duplicates: unknown[] = [] + + for (const element of x) { + if (seen.has(element)) { + duplicates.push(element) + } + seen.add(element) + } + + return duplicates +}) as Kind._$reify diff --git a/src/list/flat-map.spec.ts b/src/list/flat-map.spec.ts new file mode 100644 index 000000000..e85e2ae55 --- /dev/null +++ b/src/list/flat-map.spec.ts @@ -0,0 +1,21 @@ +import { $, Function, List, Test } from '..' + +type FlatMap_Spec = [ + /** + * Can map over a list, returning a flattened list. + */ + Test.Expect<$<$, [1, 2, 3]>, [0, 0, 1, 0, 1, 2]>, + + /** + * Identity function returns a 1-flattened list. + */ + Test.Expect<$<$, [1, 2, 3]>, [1, 2, 3]>, + + /** + * Flattening is only one level deep. + */ + Test.Expect< + $<$, [[[1, 2]], [3, 4]]>, + [[1, 2], 3, 4] + > +] diff --git a/src/list/flat-map.ts b/src/list/flat-map.ts new file mode 100644 index 000000000..4dbaf6366 --- /dev/null +++ b/src/list/flat-map.ts @@ -0,0 +1,65 @@ +import { $, Kind, List, Type } from '..' + +/** + * `FlatMap` is a type-level function that applies a mapping function to each + * element of a list, and returns a flattened list of the results (by one + * level only). + * + * Elements returned by the mapping function which are not lists will remain + * in place in the flattened list. + * + * @template F - The type-level function to apply to each element of the list. + * @template X - The list to apply the type-level function to. + * + * @returns A flattened list of the results of applying the type-level function + * to each element of the list. + * + * @example + * + * ```ts + * import { $, List, String } from "hkt-toolbelt"; + * + * type T0 = $> // [0, 0, 1, 0, 1, 2] + * ``` + */ +export type _$flatMap< + F extends Kind.Kind, + X extends unknown[], + O extends unknown[] = [] +> = X extends [infer Head, ...infer Tail] + ? $>> extends infer Result + ? Result extends List.List + ? _$flatMap + : _$flatMap + : never + : O + +interface FlatMap_T extends Kind.Kind { + f(x: Type._$cast): _$flatMap +} + +/** + * `FlatMap` is a type-level function that applies a mapping function to each + * element of a list, and returns a flattened list of the results (by one + * level only). + * + * Elements returned by the mapping function which are not lists will remain + * in place in the flattened list. + * + * @template F - The type-level function to apply to each element of the list. + * @template X - The list to apply the type-level function to. + * + * @returns A flattened list of the results of applying the type-level function + * to each element of the list. + * + * @example + * + * ```ts + * import { $, List, String } from "hkt-toolbelt"; + * + * type T0 = $> // [0, 0, 1, 0, 1, 2] + * ``` + */ +export interface FlatMap extends Kind.Kind { + f(x: Type._$cast): FlatMap_T +} diff --git a/src/list/includes.spec.ts b/src/list/includes.spec.ts index 105e32205..4132ca43b 100644 --- a/src/list/includes.spec.ts +++ b/src/list/includes.spec.ts @@ -1,58 +1,29 @@ -import { $, Conditional, Function, List, String, Test } from '..' +import { $, List, Test } from '..' type Includes_Spec = [ /** * Can determine existence of elements in a tuple */ - Test.Expect<$<$>, [1, 2, 3]>>, + Test.Expect<$<$, [1, 2, 3]>>, /** * Can determine non-existence of elements in a tuple */ - Test.ExpectNot<$<$>, [1, 2, 3]>>, + Test.ExpectNot<$<$, [1, 2, 3]>>, /** * Empty tuples always result in false on search. */ - Test.ExpectNot<$<$>, []>>, + Test.ExpectNot<$<$, []>>, /** - * Setting a constant inclusion function results in true for non-empty tuples. - */ - Test.Expect<$<$>, [1, 2, 3]>>, - - /** - * Setting a constant-false inclusion function results in false. - */ - Test.ExpectNot<$<$>, [1, 2, 3]>>, - - /** - * Can perform complex multidimensional filtering. In this example, select - * only tuples that contain at least one string. - */ - Test.Expect< - $< - $>>, - [[1, 2, 3], [1, 2, 3, 'f'], ['a', 'b', 'c']] - >, - [[1, 2, 3, 'f'], ['a', 'b', 'c']] - >, - - /** - * Non-boolean inclusion check emit an error. - */ - // @ts-expect-error - List.Includes<$>, - - /** - * Applying data that doesn't match the predicate input type emits an error. + * Applying includes to a non-tuple results in an error. */ // @ts-expect-error - $>, [1, 2, 3]>, + $<$, number>, /** - * Applying includes to a non-tuple results in an error. + * A list with a boolean element does not necessarily include 'true'. */ - // @ts-expect-error - $>, number> + Test.ExpectNot<$<$, [boolean]>> ] diff --git a/src/list/includes.ts b/src/list/includes.ts index d2429985d..9710878a9 100644 --- a/src/list/includes.ts +++ b/src/list/includes.ts @@ -1,9 +1,10 @@ -import { $, Type, Kind } from '..' +import { Conditional, Kind, Type } from '..' /** - * `_$includes` is a type-level function that checks if a list includes a certain element. + * `_$includes` is a type-level function that checks if a list includes a + * certain element. * - * @template F - The function to apply to each element. + * @template V - The value to check for. * @template X - The list to check. * @returns A boolean. * @@ -11,24 +12,23 @@ import { $, Type, Kind } from '..' * type T0 = List._$includes<$, [1, 2, 3]> // true * type T1 = List._$includes<$, [1, 2, 3]> // false */ -export type _$includes = X extends [ - infer Head, - ...infer Tail -] - ? $>> extends true - ? true - : _$includes - : false +export type _$includes = 0 extends 1 + ? never + : X extends [infer Head, ...infer Tail] + ? Conditional._$equals extends true + ? true + : _$includes + : false -interface Includes_T boolean>> - extends Kind.Kind { - f(x: Type._$cast[]>): _$includes +interface Includes_T extends Kind.Kind { + f(x: Type._$cast): _$includes } /** - * `Includes` is a type-level function that checks if a list includes a certain element. + * `Includes` is a type-level function that checks if a list includes a certain + * element. * - * @template T - The function to apply to each element. + * @template V - The value to check for. * @template X - The list to check. * @returns A boolean. * @@ -37,7 +37,5 @@ interface Includes_T boolean>> * type T1 = $<$>, [1, 2, 3]> // false */ export interface Includes extends Kind.Kind { - f( - x: Type._$cast boolean>> - ): Includes_T + f(x: this[Kind._]): Includes_T } diff --git a/src/list/includesValue.spec.ts b/src/list/includesValue.spec.ts new file mode 100644 index 000000000..5cd8f876f --- /dev/null +++ b/src/list/includesValue.spec.ts @@ -0,0 +1,18 @@ +import { $, List, Test } from '..' + +type ContainsValue_Spec = [ + /** + * Can check if a value is present in a list. + */ + Test.Expect<$<$, 2>>, + + /** + * Can check if a value is present in a list with duplicates. + */ + Test.Expect<$<$, 2>>, + + /** + * Can determine if a value is not present in a list. + */ + Test.ExpectNot<$<$, 10>> +] diff --git a/src/list/includesValue.ts b/src/list/includesValue.ts new file mode 100644 index 000000000..4c7b1f8ce --- /dev/null +++ b/src/list/includesValue.ts @@ -0,0 +1,51 @@ +import { Kind, List, Type } from '..' + +/** + * `_$includesValue` is a type-level function that takes in a list `T` and a + * value `X`, and returns a boolean indicating whether `T` contains `X`. + * + * This has opposite arguments with respect to `List.Contains`. + * + * @template T - The list to check. + * @template X - The value to check. + * + * @returns A boolean indicating whether `T` contains `X`. + * + * @example + * For example, we can use `_$includesValue` to check if a value is present in a list: + * + * ```ts + * import { List } from "hkt-toolbelt"; + * + * type Result = List._$includesValue<[1, 2, 3], 2>; // true + * ``` + */ +export type _$includesValue = List._$includes + +interface IncludesValue_T extends Kind.Kind { + f(x: this[Kind._]): _$includesValue +} + +/** + * `IncludesValue` is a type-level function that takes in a list `T` and a value + * `X`, and returns a boolean indicating whether `T` contains `X`. + * + * This has opposite arguments with respect to `Contains`. + * + * @template T - The list to check. + * @template X - The value to check. + * + * @returns A boolean indicating whether `T` contains `X`. + * + * @example + * For example, we can use `IncludesValue` to check if a value is present in a list: + * + * ```ts + * import { $, List } from "hkt-toolbelt"; + * + * type Result = $<$, 2>; // true + * ``` + */ +export interface IncludesValue extends Kind.Kind { + f(x: Type._$cast): IncludesValue_T +} diff --git a/src/list/index.ts b/src/list/index.ts index be985beaa..ef7d20d29 100644 --- a/src/list/index.ts +++ b/src/list/index.ts @@ -1,17 +1,22 @@ export * from './accumulate' export * from './at' +export * from './chunk' export * from './concat' +export * from './duplicates' export * from './every' -export * from './flatten' -export * from './flatten-n' export * from './filter' export * from './find' export * from './first' +export * from './flat-map' +export * from './flatten' +export * from './flatten-n' export * from './includes' +export * from './includesValue' +export * from './intersect' export * from './inverse-map' export * from './inverse-map-n' -export * from './iterate' export * from './is-variadic' +export * from './iterate' export * from './last' export * from './length' export * from './list' @@ -21,15 +26,18 @@ export * from './pair' export * from './pop' export * from './pop-n' export * from './push' +export * from './pushValue' export * from './range' export * from './reduce' +export * from './remove' export * from './repeat' export * from './reverse' export * from './shift' export * from './shift-n' export * from './slice' -export * from './splice' export * from './some' +export * from './splice' export * from './times' +export * from './unique' export * from './unshift' export * from './zip' diff --git a/src/list/intersect.spec.ts b/src/list/intersect.spec.ts new file mode 100644 index 000000000..79d8969cc --- /dev/null +++ b/src/list/intersect.spec.ts @@ -0,0 +1,23 @@ +import { $, List, Test } from '..' + +type Intersect_Spec = [ + /** + * Can find the common elements in two lists. + */ + Test.Expect<$<$, [1, 2, 3, 4, 5]>, [1, 2, 3]>, + + /** + * Can find the common elements in two lists, even if the lists are empty. + */ + Test.Expect<$<$, []>, []>, + + /** + * Can find the common elements in two lists, even if the lists are the same. + */ + Test.Expect<$<$, [1, 2, 3]>, [1, 2, 3]>, + + /** + * Can result in an empty list if the lists are disjoint. + */ + Test.Expect<$<$, [4, 5, 6]>, []> +] diff --git a/src/list/intersect.ts b/src/list/intersect.ts new file mode 100644 index 000000000..72d00ef83 --- /dev/null +++ b/src/list/intersect.ts @@ -0,0 +1,59 @@ +import { Kind, List, Type } from '..' + +/** + * `_$intersect` is a type-level function that takes in two lists `A` and `B`, + * and returns a list of the elements that are common to both lists. + * + * Elements are ordered in the same order as the first list. + * + * @template A - The first list. + * @template B - The second list. + * @template T - The common elements. + * + * @example + * For example, we can use `_$intersect` to find the common elements in two lists: + * + * ```ts + * import { List } from "hkt-toolbelt"; + * + * type Result = List._$intersect<[1, 2, 3], [1, 2, 3, 4, 5]>; // [1, 2, 3] + * ``` + */ +export type _$intersect< + A extends unknown[], + B extends unknown[], + O extends unknown[] = [] +> = 0 extends 1 + ? never + : A extends [infer Head, ...infer Tail] + ? List._$includes extends true + ? _$intersect + : _$intersect + : O + +interface Intersect_T extends Kind.Kind { + f(x: Type._$cast): _$intersect +} + +/** + * `Intersect` is a type-level function that takes in two lists `A` and `B`, + * and returns a list of the elements that are common to both lists. + * + * Elements are ordered in the same order as the first list. + * + * @template A - The first list. + * @template B - The second list. + * @template T - The common elements. + * + * @example + * For example, we can use `Intersect` to find the common elements in two lists: + * + * ```ts + * import { $, List } from "hkt-toolbelt"; + * + * type Result = $<$, [1, 3, 4, 5]>; // [1, 3] + * ``` + */ +export interface Intersect extends Kind.Kind { + f(x: Type._$cast): Intersect_T +} diff --git a/src/list/length.spec.ts b/src/list/length.spec.ts index 293ac3dc1..da0379a6f 100644 --- a/src/list/length.spec.ts +++ b/src/list/length.spec.ts @@ -26,3 +26,7 @@ type Length_Spec = [ */ Test.Expect<$, 1> ] + +it('should return the length of a list', () => { + expect(List.length([1, 2, 3])).toBe(3) +}) diff --git a/src/list/length.ts b/src/list/length.ts index 5d7a22a8a..e7e68e580 100644 --- a/src/list/length.ts +++ b/src/list/length.ts @@ -1,4 +1,4 @@ -import { Type, Kind } from '..' +import { Kind, Type } from '..' /** * `_$length` is a type-level function that returns the length of a list. @@ -25,3 +25,15 @@ export type _$length = T['length'] export interface Length extends Kind.Kind { f(x: Type._$cast): _$length } + +/** + * Returns the length of the given list. + * + * @example + * ```ts + * import { $, List } from "hkt-toolbelt"; + * + * const result = List.length([1, 2, 3]) // 3 + * ``` + */ +export const length = ((x: unknown[]) => x.length) as Kind._$reify diff --git a/src/list/map.spec.ts b/src/list/map.spec.ts index c72ce8118..18a861088 100644 --- a/src/list/map.spec.ts +++ b/src/list/map.spec.ts @@ -54,7 +54,7 @@ type Map_Spec = [ ] > >, - $<$, $> + $<$>, 2> ] >, [[null, 1, null], [null, 1, null]] diff --git a/src/list/pushValue.spec.ts b/src/list/pushValue.spec.ts new file mode 100644 index 000000000..b3074c8c8 --- /dev/null +++ b/src/list/pushValue.spec.ts @@ -0,0 +1,22 @@ +import { $, List, Test } from '..' + +type PushValue_Spec = [ + /** + * Can push a value to the end of a tuple. + */ + Test.Expect<$<$, 4>, [1, 2, 3, 4]>, + + /** + * Pushing to an empty tuple results in a tuple with just the pushed element. + */ + Test.Expect<$<$, 'foo'>, ['foo']>, + + /** + * Pushing to a tuple with a rest parameter results in a tuple with the + * pushed element. + */ + Test.Expect< + $<$, 'foo'>, + [1, 2, ...string[], 'foo'] + > +] diff --git a/src/list/pushValue.ts b/src/list/pushValue.ts new file mode 100644 index 000000000..f51d921ba --- /dev/null +++ b/src/list/pushValue.ts @@ -0,0 +1,39 @@ +import { Kind, Type } from '..' + +/** + * `PushValue` is a type-level function that takes in a tuple `T` and a value + * `U`, and returns a new tuple with `U` appended to the end of `T`. + * + * This is the swapped argument order of the `List.Push` function. + * + * @template T - The tuple to push the value to. + * @template U - The value to push. + * + * @example + * ```ts + * type T0 = $<$, 4> // [1, 2, 3, 4] + * ``` + */ +export type _$pushValue = [...T, U] + +interface PushValue_T extends Kind.Kind { + f(x: this[Kind._]): _$pushValue +} + +/** + * `PushValue` is a type-level function that takes in a tuple `T` and a value + * `U`, and returns a new tuple with `U` appended to the end of `T`. + * + * This is the swapped argument order of the `List.Push` function. + * + * @template T - The tuple to push the value to. + * @template U - The value to push. + * + * @example + * ```ts + * type T0 = $<$, 4> // [1, 2, 3, 4] + * ``` + */ +export interface PushValue extends Kind.Kind { + f(x: Type._$cast): PushValue_T +} diff --git a/src/list/remove.spec.ts b/src/list/remove.spec.ts new file mode 100644 index 000000000..5631ef4e2 --- /dev/null +++ b/src/list/remove.spec.ts @@ -0,0 +1,34 @@ +import { $, List, Test } from '..' + +type Remove_Spec = [ + /** + * Can remove elements from a tuple. + */ + Test.Expect<$<$, [1, 2, 3, 4, 5]>, [1, 2, 4, 5]>, + + /** + * Can remove elements from a tuple with duplicates. + */ + Test.Expect<$<$, [1, 2, 3, 2, 4, 2]>, [1, 3, 4]>, + + /** + * Can attempt to remove a non-existent element. + */ + Test.Expect<$<$, [1, 2, 3, 4, 5]>, [1, 2, 3, 4, 5]>, + + /** + * Can remove union types without affecting constituent types. + */ + Test.Expect< + $<$, ['foo' | 'bar', 'bar', 'baz', 'foo']>, + ['bar', 'baz', 'foo'] + >, + + /** + * Can remove constituent types without affecting union types. + */ + Test.Expect< + $<$, ['foo' | 'bar', 'bar', 'baz', 'foo']>, + ['foo' | 'bar', 'bar', 'baz'] + > +] diff --git a/src/list/remove.ts b/src/list/remove.ts new file mode 100644 index 000000000..b10a33d95 --- /dev/null +++ b/src/list/remove.ts @@ -0,0 +1,54 @@ +import { Conditional, Kind, Type } from '..' + +/** + * `_$remove` is a type-level function that takes in a value `X` and a list `T`, + * and returns a new list `T` with all instances of the value `X` removed. + * + * @template X - The value to remove. + * @template T - The list to remove the value from. + * + * @returns A new list `T` with all instances of the value `X` removed. + * + * @example + * For example, we can use `_$remove` to remove the value `2` from a list: + * + * ```ts + * import { List } from "hkt-toolbelt"; + * + * type Result = List._$remove<2, [1, 2, 3, 2, 4, 2]>; // [1, 3, 4] + * ``` + */ +export type _$remove< + X, + T extends unknown[], + O extends unknown[] = [] +> = T extends [infer Head, ...infer Tail] + ? Conditional._$equals extends true + ? _$remove + : _$remove + : O + +interface Remove_T extends Kind.Kind { + f(x: Type._$cast): _$remove +} + +/** + * `Remove` is a type-level function that takes in a list `T` and a value `X`, + * and returns a new list `T` with all instances of the value `X` removed. + * + * @template T - The list to remove the value from. + * @template X - The value to remove. + * @returns A new list `T` with all instances of the value `X` removed. + * + * @example + * For example, we can use `Remove` to remove the value `2` from a list: + * + * ```ts + * import { $, List } from "hkt-toolbelt"; + * + * type Result = $<$, [1, 2, 3, 2, 4, 2]>; // [1, 3, 4] + * ``` + */ +export interface Remove extends Kind.Kind { + f(x: this[Kind._]): Remove_T +} diff --git a/src/list/repeat.spec.ts b/src/list/repeat.spec.ts index 92595286e..502ba49c3 100644 --- a/src/list/repeat.spec.ts +++ b/src/list/repeat.spec.ts @@ -1,4 +1,4 @@ -import { $, Test, List } from '..' +import { $, List, Test } from '..' type Repeat_Spec = [ /** @@ -10,7 +10,7 @@ type Repeat_Spec = [ * N = 8 */ Test.Expect< - $<$, '0'>, + $<$, 8>, ['0', '0', '0', '0', '0', '0', '0', '0'] >, @@ -18,16 +18,16 @@ type Repeat_Spec = [ * N = 10 */ Test.Expect< - $<$, null>, + $<$, 10>, [null, null, null, null, null, null, null, null, null, null] >, - Test.Expect<$<$, null>, [null, null, null, null, null]>, + Test.Expect<$<$, 5>, [null, null, null, null, null]>, /** * Correctly handles tuple type input. */ Test.Expect< - $<$, $>, + $<$>, 3>, [[0, 1, 2], [0, 1, 2], [0, 1, 2]] >, @@ -35,7 +35,7 @@ type Repeat_Spec = [ * Correctly handles repeating union type input. */ Test.Expect< - $<$, string | number | undefined>, + $<$, 3>, [ string | number | undefined, string | number | undefined, @@ -46,10 +46,10 @@ type Repeat_Spec = [ /** * Returns `never` for non-natural numbers. */ - Test.Expect<$<$, 'a'>, never>, + Test.Expect<$<$, -1>, never>, /** * Returns a fixed-length tuple that is non-variadic. */ - Test.ExpectNot<$, null>>> + Test.ExpectNot<$, 10>>> ] diff --git a/src/list/repeat.stress.spec.ts b/src/list/repeat.stress.spec.ts index f5201c295..e85614eb7 100644 --- a/src/list/repeat.stress.spec.ts +++ b/src/list/repeat.stress.spec.ts @@ -1,13 +1,13 @@ -import { $, Test, List } from '..' +import { $, List, Test } from '..' type Repeat_Spec = [ /** * N = 100 */ - Test.Expect<$<$, '0'>[99], '0'>, + Test.Expect<$<$, 100>[99], '0'>, /** * N = 2137 */ - Test.Expect<$<$, '0'>[2136], '0'> + Test.Expect<$<$, 2137>[2136], '0'> ] diff --git a/src/list/repeat.ts b/src/list/repeat.ts index 6e149eb57..cf9bd3038 100644 --- a/src/list/repeat.ts +++ b/src/list/repeat.ts @@ -1,4 +1,4 @@ -import { Kind, Type, DigitList, Number, List, NaturalNumber } from '..' +import { DigitList, Kind, List, NaturalNumber, Number, Type } from '..' type _$repeat2< FILL_TYPE extends unknown, @@ -31,7 +31,10 @@ type _$repeat2< * If `N` is not a natural number, returns `never`. * * @example + * + * ```ts * type Result = List._$repeat<"a", 3>; // ["a", "a", "a"] + * ``` */ export type _$repeat< T extends unknown, @@ -41,8 +44,8 @@ export type _$repeat< : never > = RESULT -interface Repeat_T extends Kind.Kind { - f(x: Type._$cast): _$repeat +interface Repeat_T extends Kind.Kind { + f(x: Type._$cast): _$repeat } /** @@ -61,42 +64,21 @@ interface Repeat_T extends Kind.Kind { * If `N` is not a natural number, returns `never`. * * @example - * type Result = $<$, 3>; // ["a", "a", "a"] - * - * @example - * By partially applying a type to `Repeat` using {@see {@link $}} - * we can define a type-level function that can repeat that type multiple different number of times. - * - * type RepeatA = $ - * type RepeatATwice = $ // ["A", "A"] - * type RepeatAFiveTimes = $ // ["A", "A", "A", "A", "A"] - */ -/** - * `Repeat` is a type-level function that returns a tuple filled with multiple elements of a specified type. * - * It takes in two arguments: - * `T`, the type to repeat, and `N`, the number of times to repeat `T`. - * - * `Repeat` can handle an output tuple length of up to 2137, - * which is larger than 999, the maximum recursion depth limit of TypeScript. - * - * @template T - An unknown type. - * @template N - A natural number. - * @returns A list of types containing `N` counts of `T`. - * - * If `N` is not a natural number, returns `never`. - * - * @example + * ```ts * type Result = $<$, 3>; // ["a", "a", "a"] + * ``` * * @example * By partially applying a type to `Repeat` using {@see {@link $}} * we can define a type-level function that can repeat that type multiple different number of times. * + * ```ts * type RepeatA = $ * type RepeatATwice = $ // ["A", "A"] * type RepeatAFiveTimes = $ // ["A", "A", "A", "A", "A"] + * ``` */ export interface Repeat extends Kind.Kind { - f(x: Type._$cast): Repeat_T + f(x: this[Kind._]): Repeat_T } diff --git a/src/list/unique.ts b/src/list/unique.ts new file mode 100644 index 000000000..3d0b61258 --- /dev/null +++ b/src/list/unique.ts @@ -0,0 +1,41 @@ +import { Kind, List, Type } from 'hkt-toolbelt' + +/** + * `_$unique` is a type-level function that returns a new list with all + * duplicate elements removed. + * + * @template {unknown[]} T The input list. + * + * @example + * ```ts + * import { List } from 'hkt-toolbelt' + * + * type Result = List._$unique<[1, 2, 3, 2, 1]> + * // ^? [1, 2, 3] + * ``` + */ +export type _$unique< + T extends unknown[], + Result extends unknown[] = [] +> = T extends [infer Head, ...infer Tail] + ? List._$includes extends true + ? _$unique + : _$unique + : Result + +/** + * Returns a new list with all duplicate elements removed. + * + * @template {unknown[]} T The input list. + * + * @example + * ```ts + * import { $, List } from 'hkt-toolbelt' + * + * type Result = $ + * // ^? [1, 2, 3] + * ``` + */ +export interface Unique extends Kind.Kind { + f(x: Type._$cast): _$unique +} From 8c672e57fd9b42e389f1cf327102e85a748a17fb Mon Sep 17 00:00:00 2001 From: poteat Date: Tue, 24 Sep 2024 13:35:19 -0700 Subject: [PATCH 09/17] feat: add new 'loop' module --- src/loop.ts | 19 +++++++++ src/loop/index.ts | 1 + src/loop/until.spec.ts | 31 ++++++++++++++ src/loop/until.ts | 94 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 145 insertions(+) create mode 100644 src/loop.ts create mode 100644 src/loop/index.ts create mode 100644 src/loop/until.spec.ts create mode 100644 src/loop/until.ts diff --git a/src/loop.ts b/src/loop.ts new file mode 100644 index 000000000..383b95c7a --- /dev/null +++ b/src/loop.ts @@ -0,0 +1,19 @@ +export * from './loop/' + +/** + * The `Loop` module contains various utilities for working with loops. Loops + * are a type-level programming construct that allows you to repeat a block of + * code until a certain condition is met. + * + * @example + * ```ts + * import { $, NaturalNumber, Loop } from 'hkt-toolbelt' + * + * type Result = $< + * $>, + * $, + * 0 + * > // 11 + * ``` + */ +declare module './loop' {} diff --git a/src/loop/index.ts b/src/loop/index.ts new file mode 100644 index 000000000..e6e9d6b34 --- /dev/null +++ b/src/loop/index.ts @@ -0,0 +1 @@ +export * from './until' diff --git a/src/loop/until.spec.ts b/src/loop/until.spec.ts new file mode 100644 index 000000000..909bf232b --- /dev/null +++ b/src/loop/until.spec.ts @@ -0,0 +1,31 @@ +import { $, Conditional, Kind, List, Loop, NaturalNumber, Test } from '..' + +type Until_Spec = [ + /** + * Can loop until a number is greater than 10. + */ + Test.Expect< + $< + $< + $>, + NaturalNumber.Increment + >, + 0 + >, + 11 + >, + + /** + * Can handle growing tuples. + */ + Test.Expect< + $< + $< + $]>>, + $ + >, + [1] + >, + [1, 1, 1, 1, 1, 1, 1, 1, 1, 1] + > +] diff --git a/src/loop/until.ts b/src/loop/until.ts new file mode 100644 index 000000000..50a0584f6 --- /dev/null +++ b/src/loop/until.ts @@ -0,0 +1,94 @@ +import { $, Conditional, Kind, Type } from '..' + +/** + * `_$until` is a type-level function that takes in a looping clause kind, an + * update kind, and an initial value, and returns a type that represents the + * result of looping until the clause is satisfied. + * + * @template Clause - A type-level function that takes in a value and returns a + * boolean indicating whether the loop should continue or not. + * @template Updater - A type-level function that takes in a value and returns a + * new value. + * @template Initial - The initial value to start the loop with. + * + * @example + * For example, we can use `_$until` to loop until a number is greater than 10: + * + * ```ts + * import { $, NaturalNumber, Loop } from "hkt-toolbelt"; + * + * type Result = Loop._$until< + * $, + * $, + * 0 + * >; // 11 + * ``` + */ +export type _$until< + Clause extends Kind.Kind<(x: never) => boolean>, + Updater extends Kind.Kind, + Initial, + VALUE = Initial +> = 0 extends 1 + ? never + : VALUE extends never + ? never + : /** + * This check seems necessary to convince the compiler that the loop is not + * infinite, in the case of array values. + */ + Conditional._$equals< + Type._$assert['length'], + number + > extends true + ? never + : $>> extends true + ? VALUE + : _$until< + Clause, + Updater, + Initial, + $>> + > + +interface Until_T2< + Clause extends Kind.Kind<(x: never) => boolean>, + Updater extends Kind.Kind +> extends Kind.Kind { + f(x: this[Kind._]): _$until +} + +interface Until_T1 boolean>> + extends Kind.Kind { + f(x: Type._$cast): Until_T2 +} + +/** + * `Until` is a type-level function that takes in a looping clause kind, an + * update kind, and an initial value, and returns a type that represents the + * result of looping until the clause is satisfied. + * + * @template Clause - A type-level function that takes in a value and returns a + * boolean indicating whether the loop should continue or not. + * @template Updater - A type-level function that takes in a value and returns a + * new value. + * @template Initial - The initial value to start the loop with. + * + * @example + * For example, we can use `Until` to loop until a number is greater than 10: + * + * ```ts + * import { $, NaturalNumber, Loop } from "hkt-toolbelt"; + * + * type Result = $< + * $>, + * $, + * 0 + * >; // 11 + * ``` + */ +export interface Until extends Kind.Kind { + f( + x: Type._$cast boolean>> + ): Until_T1 +} From d7397e0bd222c85670f9df6e69452cde1f18485e Mon Sep 17 00:00:00 2001 From: poteat Date: Tue, 24 Sep 2024 13:40:21 -0700 Subject: [PATCH 10/17] feat: add new 'matrix' utilities --- src/matrix.ts | 14 ++++++ src/matrix/chunk.spec.ts | 45 ++++++++++++++++++ src/matrix/chunk.ts | 77 +++++++++++++++++++++++++++++++ src/matrix/columns.spec.ts | 21 +++++++++ src/matrix/columns.ts | 58 +++++++++++++++++++++++ src/matrix/combine.spec.ts | 19 ++++++++ src/matrix/combine.ts | 64 ++++++++++++++++++++++++++ src/matrix/index.ts | 5 ++ src/matrix/rows.ts | 45 ++++++++++++++++++ src/matrix/slice.ts | 94 ++++++++++++++++++++++++++++++++++++++ 10 files changed, 442 insertions(+) create mode 100644 src/matrix.ts create mode 100644 src/matrix/chunk.spec.ts create mode 100644 src/matrix/chunk.ts create mode 100644 src/matrix/columns.spec.ts create mode 100644 src/matrix/columns.ts create mode 100644 src/matrix/combine.spec.ts create mode 100644 src/matrix/combine.ts create mode 100644 src/matrix/index.ts create mode 100644 src/matrix/rows.ts create mode 100644 src/matrix/slice.ts diff --git a/src/matrix.ts b/src/matrix.ts new file mode 100644 index 000000000..7683d21e6 --- /dev/null +++ b/src/matrix.ts @@ -0,0 +1,14 @@ +export * from './matrix/' + +/** + * The `Matrix` module contains various utilities for working with matrices. + * Matrices are represented as arrays of arrays, i.e. an array of rows. + * + * @example + * ```ts + * import { $, Matrix } from 'hkt-toolbelt' + * + * type Result = $, 2>, + [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]] + >, + [ + [[1, 2]], + [[3, 4]], + [[5, 6]], + [[7, 8]], + [[9, 10]], + [[11, 12]], + [[13, 14]], + [[15, 16]] + ] + >, + + /** + * Chunking an empty matrix results in an empty array. + */ + Test.Expect<$<$<$, 1>, []>, []>, + + /** + * Chunking by 1x1 results in each element in its own matrix. + */ + Test.Expect< + $<$<$, 1>, [[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]]>, + [[[1]], [[2]], [[3]], [[4]], [[5]], [[6]], [[7]], [[8]], [[9]], [[10]]] + >, + + /** + * Chunking by 0x0 results in a 1-tuple containing the original matrix. + */ + Test.Expect< + $<$<$, 0>, [[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]]>, + [[[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]]] + > +] diff --git a/src/matrix/chunk.ts b/src/matrix/chunk.ts new file mode 100644 index 000000000..57499a20c --- /dev/null +++ b/src/matrix/chunk.ts @@ -0,0 +1,77 @@ +import { Kind, List, Type } from '..' + +/** + * `_$chunk` is a type-level function that takes in a number `N`, `M`, and a + * matrix `T`, and returns an array of matrices, where each matrix has + * dimensions `N` x `M`, i.e. N rows and M columns. + * + * Trailing submatrices have shorter dimensions if the new dimensions do not + * divide evenly into the original dimensions. + * + * @template N - The number of rows in each resulting submatrix. + * @template M - The number of columns in each resulting submatrix. + * @template T - The matrix to chunk. + * @returns An array of matrices, where each matrix has dimensions `N` x `M`. + * + * @example + * For example, we can use `_$chunk` to chunk a matrix into matrices of + * dimensions `N` x `M`: + * + * ```ts + * import { Matrix } from "hkt-toolbelt"; + * + * type Result = Matrix._$chunk<2, 2, [[1, 2, 3, 4], [5, 6, 7, 8]]]>; + * // [[[1, 2], [3, 4]], [[5, 6], [7, 8]]] + * ``` + */ +export type _$chunk< + N extends number, + M extends number, + T extends unknown[][], + CHUNKED_COLS extends unknown[][][][] = { + [K1 in keyof T]: List._$chunk + }, + CHUNKED_ROWS extends unknown[][][][][] = List._$chunk, + ZIPPED_ROWS extends unknown[][][][] = { + [K1 in keyof CHUNKED_ROWS]: List._$zip + }, + FLATTENED_ROWS extends unknown[][][] = List._$flattenN +> = FLATTENED_ROWS + +interface Chunk_T2 extends Kind.Kind { + f(x: Type._$cast): _$chunk +} + +interface Chunk_T1 extends Kind.Kind { + f(x: Type._$cast): Chunk_T2 +} + +/** + * `Chunk` is a type-level function that takes in a number `N` and a matrix `T`, + * and returns an array of matrices, where each matrix has dimensions `N` x `M`, + * i.e. N rows and M columns. + * + * Trailing submatrices have shorter dimensions if the new dimensions do not + * divide evenly into the original dimensions. + * + * @template N - The number of rows in each resulting submatrix. + * @template M - The number of columns in each resulting submatrix. + * @template T - The matrix to chunk. + * @returns An array of matrices, where each matrix has dimensions `N` x `M`. + * + * @example + * For example, we can use `Chunk` to chunk a matrix into matrices of dimensions + * `N` x `M`: + * + * ```ts + * import { $, $N, Matrix } from "hkt-toolbelt"; + * + * type Result = $< + * $N, + * [[1, 2, 3, 4], [5, 6, 7, 8]] + * >; // [[[1, 2], [3, 4]], [[5, 6], [7, 8]]] + * ``` + */ +export interface Chunk extends Kind.Kind { + f(x: Type._$cast): Chunk_T1 +} diff --git a/src/matrix/columns.spec.ts b/src/matrix/columns.spec.ts new file mode 100644 index 000000000..b692f3ee7 --- /dev/null +++ b/src/matrix/columns.spec.ts @@ -0,0 +1,21 @@ +import { $, Matrix, Test } from '..' + +type Columns_Spec = [ + /** + * Can get the columns of a matrix. + */ + Test.Expect< + $, + [[1, 4], [2, 5], [3, 6]] + >, + + /** + * Can get the columns of a matrix with a single column. + */ + Test.Expect<$, [[1, 2, 3]]>, + + /** + * Can get the columns of a matrix with a single row. + */ + Test.Expect<$, [[1], [2], [3]]> +] diff --git a/src/matrix/columns.ts b/src/matrix/columns.ts new file mode 100644 index 000000000..f1976a872 --- /dev/null +++ b/src/matrix/columns.ts @@ -0,0 +1,58 @@ +import { Kind, Type } from '..' + +/** + * const transpose = (matrix: Matrix): Matrix => + * matrix[0].map((_, i) => matrix.map((row) => row[i])); + */ + +type _$columns3 = { + [K in keyof T]: T[K][Type._$cast] +} + +type _$columns2 = { + [K in keyof FirstRow]: _$columns3 +} + +/** + * `_$columns` is a type-level function that takes in a matrix and returns the + * columns of the matrix. + * + * Since a matrix is represented as an array of arrays, i.e. an array of columns, + * this function implements the zip function, as well as the transpose function. + * + * @template T - The matrix to get the columns of. + * @returns A tuple of the columns of the matrix. + * + * @example + * For example, we can use `_$columns` to get the columns of a matrix: + * + * ```ts + * import { Matrix } from "hkt-toolbelt"; + * + * type Result = Matrix._$columns<[[1, 2, 3], [4, 5, 6]]>; // [[1, 4], [2, 5], [3, 6]] + * ``` + */ +export type _$columns = _$columns2 + +/** + * `Columns` is a type-level function that takes in a matrix and returns the + * columns of the matrix. + * + * Since a matrix is represented as an array of arrays, i.e. an array of columns, + * this function implements the zip function. + * + * @template T - The matrix to get the columns of. + * @returns A tuple of the columns of the matrix. + * + * @example + * For example, we can use `Columns` to get the columns of a matrix: + * + * ```ts + * import { $, Matrix } from "hkt-toolbelt"; + * + * type Result = $; // [[1, 4], [2, 5], [3, 6]] + * ``` + */ +export interface Columns extends Kind.Kind { + f(x: Type._$cast): _$columns +} diff --git a/src/matrix/combine.spec.ts b/src/matrix/combine.spec.ts new file mode 100644 index 000000000..c6be819fd --- /dev/null +++ b/src/matrix/combine.spec.ts @@ -0,0 +1,19 @@ +import { $, Matrix, Test } from '..' + +type Combine_Spec = [ + /** + * Can combine a matrix of matrices. + */ + Test.Expect< + $, + [[1, 9], [2, 10], [5, 13], [6, 14]] + >, + + /** + * Can combine a matrix of matrices. + */ + Test.Expect< + $, + [[3, 11], [4, 12], [7, 15], [8, 16]] + > +] diff --git a/src/matrix/combine.ts b/src/matrix/combine.ts new file mode 100644 index 000000000..9ff6e06e4 --- /dev/null +++ b/src/matrix/combine.ts @@ -0,0 +1,64 @@ +import { $, Kind, List, Matrix } from '..' + +/** + * `Combine` is a type-level function that takes in a matrix-of-matrices `T`, + * and concatenates the matrices into a single matrix. All inner matrices must + * have the same dimensions (excluding the outer dimension). + * + * @template T - The matrix-of-matrices to concatenate. + * + * @example + * type T0 = $ // [[[1, 2, "a", "b"], [5, 6, "e", "f"]], [[3, 4, "c", "d"], [7, 8, "g", "h"]]] + * // or [[M1, M2], [M3, M4]] + */ +export type Combine = $< + Kind.Pipe, + [ + Matrix.Columns, + $< + List.FlatMap, + $< + Kind.PipeWeak, + [ + List.Repeat, + $, + $< + Kind.Uncurry, + $< + Kind.PipeWeak, + [ + Kind.Apply, + $, + Kind.PipeWeak, + List.Map, + $, + Kind.PipeWeak + ] + > + > + ] + > + > + ] +> diff --git a/src/matrix/index.ts b/src/matrix/index.ts new file mode 100644 index 000000000..46ec05b93 --- /dev/null +++ b/src/matrix/index.ts @@ -0,0 +1,5 @@ +export * from './chunk' +export * from './columns' +export * from './combine' +export * from './rows' +export * from './slice' diff --git a/src/matrix/rows.ts b/src/matrix/rows.ts new file mode 100644 index 000000000..3d47569ac --- /dev/null +++ b/src/matrix/rows.ts @@ -0,0 +1,45 @@ +import { Kind, Type } from '..' + +/** + * `_$rows` is a type-level function that takes in a matrix and returns the rows + * of the matrix. + * + * Since a matrix is represented as an array of arrays, i.e. an array of rows, + * this function implements the identity function. + * + * @template T - The matrix to get the rows of. + * @returns A tuple of the rows of the matrix. + * + * @example + * For example, we can use `_$rows` to get the rows of a matrix: + * + * ```ts + * import { Matrix } from "hkt-toolbelt"; + * + * type Result = Matrix._$rows<[[1, 2, 3], [4, 5, 6]]>; // [[1, 2, 3], [4, 5, 6]] + * ``` + */ +export type _$rows = T + +/** + * `Rows` is a type-level function that takes in a matrix and returns the rows + * of the matrix. + * + * Since a matrix is represented as an array of arrays, i.e. an array of rows, + * this function implements the identity function. + * + * @template T - The matrix to get the rows of. + * @returns A tuple of the rows of the matrix. + * + * @example + * For example, we can use `Rows` to get the rows of a matrix: + * + * ```ts + * import { $, Matrix } from "hkt-toolbelt"; + * + * type Result = $; // [[1, 2, 3], [4, 5, 6]] + * ``` + */ +export interface Rows extends Kind.Kind { + f(x: Type._$cast): _$rows +} diff --git a/src/matrix/slice.ts b/src/matrix/slice.ts new file mode 100644 index 000000000..5f00d18bc --- /dev/null +++ b/src/matrix/slice.ts @@ -0,0 +1,94 @@ +import { Kind, List, Type } from '..' + +/** + * `_$slice` is a type-level function that takes in four slice coordinates and + * a matrix, and returns the slice of the matrix. Coordinates are zero-based. + * + * The slice is inclusive of the start, and exclusive of the end coordinate. + * + * @template ROW_START - The starting row of the slice. + * @template ROW_END - The ending row of the slice. + * @template COL_START - The starting column of the slice. + * @template COL_END - The ending column of the slice. + * @template T - The matrix to get the slice of. + * @returns A tuple of the slice of the matrix. + * + * @example + * For example, we can use `_$slice` to get a slice of a matrix: + * + * ```ts + * import { Matrix } from "hkt-toolbelt"; + * + * type Result = Matrix._$slice<1, 2, 1, 2, [[1, 2, 3], [4, 5, 6]]]; // [[2, 3], [5, 6]] + * ``` + */ +export type _$slice< + ROW_START extends number, + ROW_END extends number, + COL_START extends number, + COL_END extends number, + T extends unknown[][], + SLICED_ROWS extends unknown[][] = List._$slice, + SLICED_COLS extends unknown[][] = { + [K in keyof SLICED_ROWS]: List._$slice + } +> = SLICED_COLS + +interface Slice_T4< + ROW_START extends number, + ROW_END extends number, + COL_START extends number, + COL_END extends number +> extends Kind.Kind { + f( + x: Type._$cast + ): _$slice +} + +interface Slice_T3< + ROW_START extends number, + ROW_END extends number, + COL_START extends number +> extends Kind.Kind { + f( + x: Type._$cast + ): Slice_T4 +} + +interface Slice_T2 + extends Kind.Kind { + f( + x: Type._$cast + ): Slice_T3 +} + +interface Slice_T1 extends Kind.Kind { + f(x: Type._$cast): Slice_T2 +} + +/** + * `Slice` is a type-level function that takes in four slice coordinates and + * a matrix, and returns the slice of the matrix. Coordinates are zero-based. + * + * @template ROW_START - The starting row of the slice. + * @template ROW_END - The ending row of the slice. + * @template COL_START - The starting column of the slice. + * @template COL_END - The ending column of the slice. + * @template T - The matrix to get the slice of. + * @returns A tuple of the slice of the matrix. + * + * @example + * For example, we can use `Slice` to get a slice of a matrix: + * + * ```ts + * import { $, $N, Matrix } from "hkt-toolbelt"; + * + * type Result = $< + * $N, + * [[1, 2, 3], [4, 5, 6]] + * >; // [[2, 3], [5, 6]] + * ``` + */ +export interface Slice extends Kind.Kind { + f(x: Type._$cast): Slice_T1 +} From 79f6b6ad1501c0dc0ee4c156295a5a0174cd3975 Mon Sep 17 00:00:00 2001 From: poteat Date: Tue, 24 Sep 2024 13:43:49 -0700 Subject: [PATCH 11/17] feat: add various new 'type' utilities for union and intersection --- src/type/index.ts | 4 ++++ src/type/intersect.spec.ts | 26 ++++++++++++++++++++++++ src/type/intersect.ts | 37 +++++++++++++++++++++++++++++++++++ src/type/intersectAll.spec.ts | 31 +++++++++++++++++++++++++++++ src/type/intersectAll.ts | 36 ++++++++++++++++++++++++++++++++++ src/type/union.spec.ts | 27 +++++++++++++++++++++++++ src/type/union.ts | 37 +++++++++++++++++++++++++++++++++++ src/type/unionAll.spec.ts | 27 +++++++++++++++++++++++++ src/type/unionAll.ts | 33 +++++++++++++++++++++++++++++++ 9 files changed, 258 insertions(+) create mode 100644 src/type/intersect.spec.ts create mode 100644 src/type/intersect.ts create mode 100644 src/type/intersectAll.spec.ts create mode 100644 src/type/intersectAll.ts create mode 100644 src/type/union.spec.ts create mode 100644 src/type/union.ts create mode 100644 src/type/unionAll.spec.ts create mode 100644 src/type/unionAll.ts diff --git a/src/type/index.ts b/src/type/index.ts index 0d7ea72ff..cbc1a4b8f 100644 --- a/src/type/index.ts +++ b/src/type/index.ts @@ -2,5 +2,9 @@ export * from './assert' export * from './cast' export * from './display' export * from './infer' +export * from './intersect' +export * from './intersectAll' export * from './is-never' +export * from './union' +export * from './unionAll' export * from './value-of' diff --git a/src/type/intersect.spec.ts b/src/type/intersect.spec.ts new file mode 100644 index 000000000..4370b32f6 --- /dev/null +++ b/src/type/intersect.spec.ts @@ -0,0 +1,26 @@ +import { $, Test, Type } from '..' + +type Intersect_Spec = [ + /** + * Can intersect two types. + */ + Test.Expect< + $<$, { bar: string }>, + { foo: string; bar: string } + >, + + /** + * Can intersect with an empty type. + */ + Test.Expect<$<$, { bar: string }>, { bar: string }>, + + /** + * Can intersect with non-object types. + */ + Test.Expect< + $<$, { bar: string }>, + string & { + bar: string + } + > +] diff --git a/src/type/intersect.ts b/src/type/intersect.ts new file mode 100644 index 000000000..900e89e37 --- /dev/null +++ b/src/type/intersect.ts @@ -0,0 +1,37 @@ +import { Kind } from '..' + +/** + * `_$intersect` is a type-level function that takes two types `A` and `B`, and + * returns the intersection of `A` and `B`. + * + * @template A - The first type to intersect. + * @template B - The second type to intersect. + * + * @example + * ```ts + * type T0 = _$intersect<[], number> // [] & number + * type T1 = _$intersect // string + * ``` + */ +export type _$intersect = A & B + +interface Intersect_T extends Kind.Kind { + f(x: this[Kind._]): _$intersect +} + +/** + * `Intersect` is a type-level function that takes two types `A` and `B`, and + * returns the intersection of `A` and `B`. + * + * @template A - The first type to intersect. + * @template B - The second type to intersect. + * + * @example + * ```ts + * type T0 = $ // [] & number + * type T1 = $ // string + * ``` + */ +export interface Intersect extends Kind.Kind { + f(x: this[Kind._]): Intersect_T +} diff --git a/src/type/intersectAll.spec.ts b/src/type/intersectAll.spec.ts new file mode 100644 index 000000000..da9883283 --- /dev/null +++ b/src/type/intersectAll.spec.ts @@ -0,0 +1,31 @@ +import { $, Test, Type } from '..' + +type IntersectAll_Spec = [ + /** + * Can intersect all types in a tuple. + */ + Test.Expect< + $, + { foo: string; bar: string } + >, + + /** + * Intersecting an empty tuple results in `unknown` + */ + Test.Expect<$, unknown>, + + /** + * Can intersect with non-object types. + */ + Test.Expect< + $, + string & { + bar: string + } + >, + + /** + * An intersection of a 1-tuple is the identity of the element. + */ + Test.Expect<$, string> +] diff --git a/src/type/intersectAll.ts b/src/type/intersectAll.ts new file mode 100644 index 000000000..f1ac816ab --- /dev/null +++ b/src/type/intersectAll.ts @@ -0,0 +1,36 @@ +import { Kind, Type } from '..' + +/** + * `_$intersectAll` is a type-level function that takes a tuple of types `T`, and + * returns the intersection of all types in `T`. + * + * @template T - The tuple of types to intersect. + * + * @example + * ```ts + * type T0 = _$intersectAll<[number, string]> // number & string + * type T1 = _$intersectAll<[string, string]> // string + * ``` + */ +export type _$intersectAll = T extends [ + infer Head, + ...infer Tail +] + ? _$intersectAll + : O + +/** + * `IntersectAll` is a type-level function that takes a tuple of types `T`, and + * returns the intersection of all types in `T`. + * + * @template T - The tuple of types to intersect. + * + * @example + * ```ts + * type T0 = $ // number & string + * type T1 = $ // string + * ``` + */ +export interface IntersectAll extends Kind.Kind { + f(x: Type._$cast): _$intersectAll +} diff --git a/src/type/union.spec.ts b/src/type/union.spec.ts new file mode 100644 index 000000000..21c486b56 --- /dev/null +++ b/src/type/union.spec.ts @@ -0,0 +1,27 @@ +import { $, Test, Type } from '..' + +type Union_Spec = [ + /** + * Can union two types. + */ + Test.Expect< + $<$, { bar: string }>, + { foo: string } | { bar: string } + >, + + /** + * Can union with an empty type. + */ + Test.Expect<$<$, { bar: string }>, {} | { bar: string }>, + + /** + * Can union with non-object types. + */ + Test.Expect< + $<$, { bar: string }>, + | string + | { + bar: string + } + > +] diff --git a/src/type/union.ts b/src/type/union.ts new file mode 100644 index 000000000..d1ba2c05b --- /dev/null +++ b/src/type/union.ts @@ -0,0 +1,37 @@ +import { Kind } from '..' + +/** + * `_$union` is a type-level function that takes two types `A` and `B`, and + * returns the union of `A` and `B`. + * + * @template A - The first type to union. + * @template B - The second type to union. + * + * @example + * ```ts + * type T0 = _$union<[], number> // number + * type T1 = _$union // string + * ``` + */ +export type _$union = A | B + +interface Union_T extends Kind.Kind { + f(x: this[Kind._]): _$union +} + +/** + * `Union` is a type-level function that takes two types `A` and `B`, and + * returns the union of `A` and `B`. + * + * @template A - The first type to union. + * @template B - The second type to union. + * + * @example + * ```ts + * type T0 = $ // number + * type T1 = $ // string + * ``` + */ +export interface Union extends Kind.Kind { + f(x: this[Kind._]): Union_T +} diff --git a/src/type/unionAll.spec.ts b/src/type/unionAll.spec.ts new file mode 100644 index 000000000..835f2ddfb --- /dev/null +++ b/src/type/unionAll.spec.ts @@ -0,0 +1,27 @@ +import { $, Test, Type } from '..' + +type UnionAll_Spec = [ + /** + * Can union all types in a tuple. + */ + Test.Expect< + $, + { foo: string } | { bar: string } + >, + + /** + * Unioning an empty tuple results in `never`. + */ + Test.Expect<$, never>, + + /** + * Can union with non-object types. + */ + Test.Expect< + $, + | string + | { + bar: string + } + > +] diff --git a/src/type/unionAll.ts b/src/type/unionAll.ts new file mode 100644 index 000000000..da06abfad --- /dev/null +++ b/src/type/unionAll.ts @@ -0,0 +1,33 @@ +import { Kind, Type } from '..' + +/** + * `_$unionAll` is a type-level function that takes a tuple of types `T`, and + * returns the union of all types in `T`. + * + * This is simply equivalent to `T[number]`. + * + * @template T - The tuple of types to union. + * + * @example + * ```ts + * type T0 = _$unionAll<[number, string]> // number | string + * type T1 = _$unionAll<[string, string]> // string + * ``` + */ +export type _$unionAll = T[number] + +/** + * `UnionAll` is a type-level function that takes a tuple of types `T`, and + * returns the union of all types in `T`. + * + * @template T - The tuple of types to union. + * + * @example + * ```ts + * type T0 = $ // number | string + * type T1 = $ // string + * ``` + */ +export interface UnionAll extends Kind.Kind { + f(x: Type._$cast): _$unionAll +} From 1e993e2d85376ef1582708d4a4df28a5efa03c14 Mon Sep 17 00:00:00 2001 From: poteat Date: Tue, 24 Sep 2024 13:45:32 -0700 Subject: [PATCH 12/17] feat: implement fibonacci type-level function --- .../fibonacci-sequence.spec.ts | 11 ++++++ .../fibonacci-sequence.ts | 34 +++++++++++++++++++ src/natural-number/increment.spec.ts | 6 +++- src/natural-number/increment.ts | 31 ++++++++++++----- 4 files changed, 72 insertions(+), 10 deletions(-) create mode 100644 src/natural-number-theory/fibonacci-sequence.spec.ts create mode 100644 src/natural-number-theory/fibonacci-sequence.ts diff --git a/src/natural-number-theory/fibonacci-sequence.spec.ts b/src/natural-number-theory/fibonacci-sequence.spec.ts new file mode 100644 index 000000000..ea1a4b035 --- /dev/null +++ b/src/natural-number-theory/fibonacci-sequence.spec.ts @@ -0,0 +1,11 @@ +import { $, List, NaturalNumberTheory, Test } from '..' + +type FibonacciSequence_Spec = [ + /** + * Fibonacci sequence of 100 + */ + Test.Expect< + $, [0, 1]>>, + 218922995834555169026n + > +] diff --git a/src/natural-number-theory/fibonacci-sequence.ts b/src/natural-number-theory/fibonacci-sequence.ts new file mode 100644 index 000000000..29c09e71b --- /dev/null +++ b/src/natural-number-theory/fibonacci-sequence.ts @@ -0,0 +1,34 @@ +import { $, Conditional, Kind, List, Loop, NaturalNumber } from '..' + +type GetLastTwo = $, List.Last]> + +type SumLastTwo = $]> + +type AppendNewSum = $< + Kind.Pipe, + [$, $] +> + +type LengthIsX = $< + Kind.PipeWeak, + [Conditional.Equals, $, Kind.Pipe] +> + +/** + * `FibonacciSequence` is a type-level function that generates a sequence of + * Fibonacci numbers, given a desired resultant length, and an initial sequence. + * + * @example + * ```ts + * import { $, NaturalNumberTheory } from "hkt-toolbelt"; + * + * type Result = $< + * $, + * [0, 1] + * >; // [0, 1, 1, 2, 3] + * ``` + */ +export type FibnonacciSequence = $< + Kind.PipeWeak, + [LengthIsX, Loop.Until, $] +> diff --git a/src/natural-number/increment.spec.ts b/src/natural-number/increment.spec.ts index ab28784aa..3f2516923 100644 --- a/src/natural-number/increment.spec.ts +++ b/src/natural-number/increment.spec.ts @@ -1,4 +1,4 @@ -import { $, Test, NaturalNumber } from '..' +import { $, NaturalNumber, Test } from '..' type Increment_Spec = [ /** @@ -26,3 +26,7 @@ type Increment_Spec = [ */ Test.Expect<$, never> ] + +it('should return the result of incrementing a natural number', () => { + expect(NaturalNumber.increment(1)).toBe(2) +}) diff --git a/src/natural-number/increment.ts b/src/natural-number/increment.ts index 68205be3f..42f2c865c 100644 --- a/src/natural-number/increment.ts +++ b/src/natural-number/increment.ts @@ -1,12 +1,12 @@ -import { Type, Kind, DigitList, NaturalNumber, Number } from '..' +import { DigitList, Kind, NaturalNumber, Number as Number_, Type } from '..' /** * `_$increment` is a type-level function that takes in a natural number `A` and * returns a new natural number representing the result of incrementing the input * natural number by 1. If the input is zero, the result will be zero. * - * @template {Number.Number} A - A natural number to increment. - * @returns {Number.Number} A natural number. + * @template {Number_.Number} A - A natural number to increment. + * @returns {Number_.Number} A natural number. * * @example * For example, we can use `_$increment` to increment the number 42 by 1. @@ -28,10 +28,10 @@ import { Type, Kind, DigitList, NaturalNumber, Number } from '..' * ``` */ export type _$increment< - A extends Number.Number, + A extends Number_.Number, A_LIST extends DigitList.DigitList = NaturalNumber._$toList, INCREMENT extends DigitList.DigitList = DigitList._$increment, - RESULT extends Number.Number = Number._$fromString< + RESULT extends Number_.Number = Number_._$fromString< DigitList._$toString > > = RESULT @@ -40,8 +40,8 @@ export type _$increment< * `Increment` is a type-level function that increments a natural number type. * It returns the incremented natural number. * - * @template {Number.Number} A - A natural number to increment. - * @returns {Number.Number} A natural number or `never`. + * @template {Number_.Number} A - A natural number to increment. + * @returns {Number_.Number} A natural number or `never`. * * If the input is not zero or a natural number, `never` is returned. * @@ -65,6 +65,19 @@ export type _$increment< */ export interface Increment extends Kind.Kind { f( - x: Type._$cast - ): Number._$isNatural extends true ? _$increment : never + x: Type._$cast + ): Number_._$isNatural extends true ? _$increment : never } + +/** + * Given a natural number `N`, return the result of incrementing `N`. + * + * @example + * ```ts + * import { NaturalNumber } from "hkt-toolbelt"; + * + * const result = NaturalNumber.increment(1) // 2 + * ``` + */ +export const increment = ((n: Number_.Number) => + Number(n) + 1) as Kind._$reify From 79ad92446be9c82880d81df7eb51c7221b419899 Mon Sep 17 00:00:00 2001 From: poteat Date: Tue, 24 Sep 2024 13:47:24 -0700 Subject: [PATCH 13/17] feat: add various sudoku type-level functions --- changelog.md | 29 +++++ src/index.ts | 71 +++++------ src/natural-number-theory/index.ts | 5 +- .../is-valid-sudoku.spec.ts | 115 ++++++++++++++++++ src/natural-number-theory/is-valid-sudoku.ts | 51 ++++++++ .../mask-invalid-sudoku-places.spec.ts | 96 +++++++++++++++ .../mask-invalid-sudoku-places.ts | 86 +++++++++++++ 7 files changed, 411 insertions(+), 42 deletions(-) create mode 100644 src/natural-number-theory/is-valid-sudoku.spec.ts create mode 100644 src/natural-number-theory/is-valid-sudoku.ts create mode 100644 src/natural-number-theory/mask-invalid-sudoku-places.spec.ts create mode 100644 src/natural-number-theory/mask-invalid-sudoku-places.ts diff --git a/changelog.md b/changelog.md index d081fbd87..7346f130c 100644 --- a/changelog.md +++ b/changelog.md @@ -2,6 +2,35 @@ ## [Unreleased] +## [0.24.0] + +- Add various `Kind` utilities: + - Add `Kind.Juxt` for performing multiple calculations on a single input. + - Add `Kind.PipeWeak` for a more flexible pipe operation with less checks. +- Add various `List` utilities: + - Add `List.Chunk` for chunking lists into specified sizes of sublists. + - Add `List.Duplicates` to identify duplicate values in a list. + - Add `List.FlatMap` that maps over a kind and flattens the result one level. + - Add `List.IncludesValue` as an argument swap of `List.Includes`. + - Add `List.Intersect` to get common elements between two lists. + - Add `List.PushValue` as an argument swap of `List.Push`. + - Add `List.Remove` to filter out every instance of a value from a list. + - Add `List.Unique` to return a list with all duplicate elements removed. +- Add new `Loop` module with an initial `Loop.Until` utility. +- Add new `Matrix` module for dealing with two-dimensional arrays: + - Add `Matrix.Chunk` to chunk a matrix into a list of matrices. + - Add `Matrix.Columns` to get the columns of a matrix. + - Add `Matrix.Combine` to combine to merge a matrix of matrices into a single matrix. + - Add `Matrix.Rows` to get the rows of a matrix. + - Add `Matrix.Slice` to slice a matrix to get a submatrix using four indices. +- Add new `Type` utilities for intersection and union types: + - Add `Type.Intersect` to get the intersection of two types. + - Add `Type.Union` to get the union of two types. + - Add `Type.IntersectAll` to get the intersection of all types in a tuple. + - Add `Type.UnionAll` to get the union of all types in a tuple. +- **[Breaking]** Swap argument order of `List.Repeat` to match documentation. +- **[Breaking]** Change `List.Includes` to take in direct value (since `List.Some` already exists). + ## [0.23.1] - Add `Type.Assert` utility for strict type assertions. diff --git a/src/index.ts b/src/index.ts index 3a9c246b0..64a3a09ac 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,62 +1,48 @@ -import * as $ from './$' export { $, $$, $N } from './$' - -import * as Boolean from './boolean' export * as Boolean from './boolean' - -import * as Combinator from './combinator' export * as Combinator from './combinator' - -import * as Conditional from './conditional' export * as Conditional from './conditional' - -import * as DigitList from './digit-list' -export * as DigitList from './digit-list' - -import * as Digit from './digit' export * as Digit from './digit' - -import * as Function from './function' +export * as DigitList from './digit-list' export * as Function from './function' - -import * as Integer from './integer' export * as Integer from './integer' - -import * as Kind from './kind' export * as Kind from './kind' - -import * as List from './list' export * as List from './list' - -import * as NaturalNumberTheory from './natural-number-theory' -export * as NaturalNumberTheory from './natural-number-theory' - -import * as NaturalNumber from './natural-number' +export * as Loop from './loop' +export * as Matrix from './matrix' export * as NaturalNumber from './natural-number' - -import * as Number from './number' +export * as NaturalNumberTheory from './natural-number-theory' export * as Number from './number' - -import * as Object from './object' export * as Object from './object' - -import * as Parser from './parser' export * as Parser from './parser' - -import * as Stress from './stress' export * as Stress from './stress' - -import * as String from './string' export * as String from './string' - -import * as Test from './test' export * as Test from './test' - -import * as Type from './type' export * as Type from './type' +export * as Union from './union' +import * as $ from './$' +import * as Boolean from './boolean' +import * as Combinator from './combinator' +import * as Conditional from './conditional' +import * as Digit from './digit' +import * as DigitList from './digit-list' +import * as Function from './function' +import * as Integer from './integer' +import * as Kind from './kind' +import * as List from './list' +import * as Loop from './loop' +import * as Matrix from './matrix' +import * as NaturalNumber from './natural-number' +import * as NaturalNumberTheory from './natural-number-theory' +import * as Number from './number' +import * as Object_ from './object' +import * as Parser from './parser' +import * as Stress from './stress' +import * as String from './string' +import * as Test from './test' +import * as Type from './type' import * as Union from './union' -export * as Union from './union' const _ = { ...$, @@ -66,12 +52,15 @@ const _ = { DigitList, Digit, Function, + Integer, Kind, List, + Loop, + Matrix, NaturalNumberTheory, NaturalNumber, Number, - Object, + Object: Object_, Parser, Stress, String, diff --git a/src/natural-number-theory/index.ts b/src/natural-number-theory/index.ts index 73cc2db5f..0c41b1176 100644 --- a/src/natural-number-theory/index.ts +++ b/src/natural-number-theory/index.ts @@ -1,4 +1,7 @@ -export * from './collatz-sequence' export * from './collatz' +export * from './collatz-sequence' export * from './factorial' +export * from './fibonacci-sequence' export * from './fizzbuzz' +export * from './is-valid-sudoku' +export * from './mask-invalid-sudoku-places' diff --git a/src/natural-number-theory/is-valid-sudoku.spec.ts b/src/natural-number-theory/is-valid-sudoku.spec.ts new file mode 100644 index 000000000..8090dea56 --- /dev/null +++ b/src/natural-number-theory/is-valid-sudoku.spec.ts @@ -0,0 +1,115 @@ +import { $, NaturalNumberTheory, Test } from '..' + +type ValidSudoku_Spec = [ + /** + * A valid Sudoku puzzle + */ + Test.Expect< + $< + NaturalNumberTheory.IsValidSudoku, + [ + [5, 3, 4, 6, 7, 8, 9, 1, 2], + [6, 7, 2, 1, 9, 5, 3, 4, 8], + [1, 9, 8, 3, 4, 2, 5, 6, 7], + [8, 5, 9, 7, 6, 1, 4, 2, 3], + [4, 2, 6, 0, 5, 0, 7, 0, 0], + [0, 1, 3, 9, 2, 4, 0, 5, 6], + [9, 6, 1, 5, 3, 7, 2, 8, 0], + [2, 8, 0, 4, 1, 9, 6, 3, 5], + [3, 0, 0, 2, 8, 6, 1, 7, 9] + ] + > + >, + + /** + * An invalid Sudoku puzzle, based on size. + */ + Test.Expect< + $, + false + >, + + /** + * A Sudoku puzzle of all zeroes is valid. + */ + Test.Expect< + $< + NaturalNumberTheory.IsValidSudoku, + [ + [0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0] + ] + >, + true + >, + + /** + * An invalid Sudoku puzzle, based on row duplication. + */ + Test.Expect< + $< + NaturalNumberTheory.IsValidSudoku, + [ + [1, 0, 0, 0, 0, 0, 0, 0, 1], // Row with duplicate values 1 + [0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0] + ] + >, + false + >, + + /** + * An invalid Sudoku puzzle, based on column duplication. + */ + Test.Expect< + $< + NaturalNumberTheory.IsValidSudoku, + [ + [1, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0], + [1, 0, 0, 0, 0, 0, 0, 0, 0] + ] + >, + false + >, + + /** + * An invalid Sudoku puzzle, based on box duplication. + */ + Test.Expect< + $< + NaturalNumberTheory.IsValidSudoku, + [ + [1, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 1, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0] + ] + >, + false + > +] diff --git a/src/natural-number-theory/is-valid-sudoku.ts b/src/natural-number-theory/is-valid-sudoku.ts new file mode 100644 index 000000000..9ae3d8933 --- /dev/null +++ b/src/natural-number-theory/is-valid-sudoku.ts @@ -0,0 +1,51 @@ +import { $, Boolean, Conditional, Function, Kind, List, Matrix } from '..' + +type HasAllUniqueElements = $< + Kind.Pipe, + [List.Duplicates, List.Length, $] +> + +type HasAllUniqueElementsExcludingZero = $< + Kind.Pipe, + [$>, HasAllUniqueElements] +> + +type LengthIsNine = $]> + +type IsValidSet = $< + Kind.Pipe, + [ + $, + Boolean.AndAll + ] +> + +type GetRows = Function.Identity + +type GetColumns = Matrix.Columns + +type GetBoxes = $< + Kind.Pipe, + [$<$, 3>, $>] +> + +/** + * A type-level function that checks if a given 2D array is a valid Sudoku + * puzzle. + * + * A Sudoku puzzle is a 9x9 grid of numbers where each row, column, and 3x3 box + * contains the numbers 1-9 exactly once. + * + * The number 0 represents an uncompleted cell, which is considered valid. + * + * @template T - The 2D array to check. + */ +export type IsValidSudoku = $< + Kind.Pipe, + [ + $, + $, + $, + Boolean.AndAll + ] +> diff --git a/src/natural-number-theory/mask-invalid-sudoku-places.spec.ts b/src/natural-number-theory/mask-invalid-sudoku-places.spec.ts new file mode 100644 index 000000000..35fc90d23 --- /dev/null +++ b/src/natural-number-theory/mask-invalid-sudoku-places.spec.ts @@ -0,0 +1,96 @@ +import { $, NaturalNumberTheory, Test } from '..' + +type MaskInvalidSudokuPlaces_Spec = [ + /** + * A valid Sudoku puzzle results in the same puzzle. + */ + Test.Expect< + $< + NaturalNumberTheory.MaskInvalidSudokuPlaces, + [ + [5, 3, 4, 6, 7, 8, 9, 1, 2], + [6, 7, 2, 1, 9, 5, 3, 4, 8], + [1, 9, 8, 3, 4, 2, 5, 6, 7], + [8, 5, 9, 7, 6, 1, 4, 2, 3], + [4, 2, 6, 0, 5, 0, 7, 0, 0], + [0, 1, 3, 9, 2, 4, 0, 5, 6], + [9, 6, 1, 5, 3, 7, 2, 8, 0], + [2, 8, 0, 4, 1, 9, 6, 3, 5], + [3, 0, 0, 2, 8, 6, 1, 7, 9] + ] + >, + [ + [5, 3, 4, 6, 7, 8, 9, 1, 2], + [6, 7, 2, 1, 9, 5, 3, 4, 8], + [1, 9, 8, 3, 4, 2, 5, 6, 7], + [8, 5, 9, 7, 6, 1, 4, 2, 3], + [4, 2, 6, 0, 5, 0, 7, 0, 0], + [0, 1, 3, 9, 2, 4, 0, 5, 6], + [9, 6, 1, 5, 3, 7, 2, 8, 0], + [2, 8, 0, 4, 1, 9, 6, 3, 5], + [3, 0, 0, 2, 8, 6, 1, 7, 9] + ] + >, + + /** + * An invalid Sudoku puzzle, based on row duplication. + */ + Test.Expect< + $< + NaturalNumberTheory.MaskInvalidSudokuPlaces, + [ + [1, 0, 0, 0, 0, 0, 0, 0, 1], // Row with duplicate values 1 + [0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0] + ] + >, + [ + [never, 0, 0, 0, 0, 0, 0, 0, never], + [0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0] + ] + >, + + /** + * Can handle cascading failures. + */ + Test.Expect< + $< + NaturalNumberTheory.MaskInvalidSudokuPlaces, + [ + [1, 0, 0, 0, 0, 0, 0, 0, 1], // Row with duplicate values 1 + [0, 0, 0, 0, 0, 0, 0, 0, 0], + [1, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0] + ] + >, + [ + [never, 0, 0, 0, 0, 0, 0, 0, never], + [0, 0, 0, 0, 0, 0, 0, 0, 0], + [never, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0] + ] + > +] diff --git a/src/natural-number-theory/mask-invalid-sudoku-places.ts b/src/natural-number-theory/mask-invalid-sudoku-places.ts new file mode 100644 index 000000000..7167124cc --- /dev/null +++ b/src/natural-number-theory/mask-invalid-sudoku-places.ts @@ -0,0 +1,86 @@ +import { $, Conditional, Function, Kind, List, Matrix, Type } from '..' + +// Given a predicate F and a value X, return F(X) ? never : X +type NeverIf = $< + Kind.Pipe, + [ + Conditional.If, + $, Function.Identity]> + ] +> + +// Given a tuple T and a value X, return T.contains(X) ? never : X +type NeverIfEqualToAnyOf = $ + +// Given a tuple T, get all duplicate values excluding the value 0. +type DuplicatesExcludingZero = $< + Kind.Pipe, + [List.Duplicates, $] +> + +// Given a tuple T, map all duplicate values to the value `never`. +type NeverIfDuplicate = $< + Kind.Pipe, + [ + $< + Kind.Juxt, + [ + $, + Function.Identity + ] + >, + $ + ] +> + +// Mask duplicate values to never for each row. +type ValidateRows = $ + +// Mask duplicate values to never for each column. +type ValidateColumns = $< + Kind.PipeWeak, + [Matrix.Columns, ValidateRows, Matrix.Columns] +> + +// Given a list of nine 3x3 boxes, combine them into a matrix. +type BuildFromBoxes = $< + Kind.Pipe, + [ + $>, + $, + Matrix.Columns, + Matrix.Combine + ] +> + +// Get all nine 3x3 boxes from a Sudoku puzzle. +type GetBoxes = $< + Kind.Pipe, + [$<$, 3>, $>] +> + +// Mask duplicate values to never for each 3x3 box. +type ValidateBoxes = $ + +// Given a list of rows, intersect each element pairwise. +type IntersectRows = $< + Kind.Pipe, + [Matrix.Columns, $] +> + +// Given a list of matrices, intersect each element pairwise. +type IntersectMatrices = $< + Kind.Pipe, + [Matrix.Columns, $] +> + +/** + * Given a 9x9 grid of numbers, mask out all invalid Sudoku places to 'never'. + */ +export type MaskInvalidSudokuPlaces = $< + Kind.Pipe, + [ + $, + IntersectMatrices + ] +> From ddd95bb272be5d9e0bcd29d5948c6ca65b5a852b Mon Sep 17 00:00:00 2001 From: poteat Date: Tue, 24 Sep 2024 13:59:49 -0700 Subject: [PATCH 14/17] docs: mark changelog entry as unreleased --- changelog.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/changelog.md b/changelog.md index 7346f130c..6ca53df48 100644 --- a/changelog.md +++ b/changelog.md @@ -2,8 +2,6 @@ ## [Unreleased] -## [0.24.0] - - Add various `Kind` utilities: - Add `Kind.Juxt` for performing multiple calculations on a single input. - Add `Kind.PipeWeak` for a more flexible pipe operation with less checks. From 971036cbe5741cd64f61bcce67be74475df04c41 Mon Sep 17 00:00:00 2001 From: poteat Date: Tue, 24 Sep 2024 14:02:54 -0700 Subject: [PATCH 15/17] fix: unused variable linting error --- src/conditional/if.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/conditional/if.ts b/src/conditional/if.ts index c5c232b56..33cb345aa 100644 --- a/src/conditional/if.ts +++ b/src/conditional/if.ts @@ -1,5 +1,4 @@ import { $, Kind, Type } from '..' -import { InputOf } from '../kind' /** * `_$if` is a type-level function that evaluates a predicate `Predicate` with From 05ee4f477b5fc8fdc0b9b0aaacd9e3720e3c11b0 Mon Sep 17 00:00:00 2001 From: poteat Date: Tue, 24 Sep 2024 14:05:14 -0700 Subject: [PATCH 16/17] feat: update typedoc --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 3ae2deb26..3a9981fa2 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,8 @@ "mustache": "^4.2.0", "prettier": "^3.2.5", "prettier-plugin-organize-imports": "^3.2.4", - "ts-jest": "^29.2.5" + "ts-jest": "^29.2.5", + "typedoc": "^0.26.7" }, "dependencies": { "typescript": "^5.5.4" From ac5621d567f551698f3529312838a8244c8dd3fc Mon Sep 17 00:00:00 2001 From: poteat Date: Tue, 24 Sep 2024 14:09:47 -0700 Subject: [PATCH 17/17] feat: allocate more memory for doc gen --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 3a9981fa2..13b35d187 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "test": "NODE_OPTIONS=--max-old-space-size=8192 tsc --project tsconfig.spec.json", "stress": "NODE_OPTIONS=--max-old-space-size=24576 tsc --project tsconfig.stress.json", "build": "./build.sh", - "build:docs": "typedoc --skipErrorChecking", + "build:docs": "NODE_OPTIONS=--max-old-space-size=8192 typedoc --skipErrorChecking", "precommit": "npm run lint-check && npm run test", "prepush": "npm run lint && npm run test && npm run stress", "lint-check": "npm run prettier-check && npm run eslint-check",