-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'main' of github.com:poteat/hkt-toolbelt
- Loading branch information
Showing
68 changed files
with
2,695 additions
and
31 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
import { $, Test, Integer } from '..' | ||
|
||
type Negate_Spec = [ | ||
/** | ||
* Can get the sign of a positive number. | ||
*/ | ||
Test.Expect<$<Integer.Negate, 42>, -42>, | ||
|
||
/** | ||
* Can get the sign of a negative number. | ||
*/ | ||
Test.Expect<$<Integer.Negate, -42>, 42>, | ||
|
||
/** | ||
* Can get the sign of zero. | ||
*/ | ||
Test.Expect<$<Integer.Negate, 0>, 0>, | ||
|
||
/** | ||
* Evaluating the 'number' type properly. | ||
*/ | ||
Test.Expect<$<Integer.Negate, number>, number> | ||
] | ||
|
||
it('should return the negation of a number', () => { | ||
expect(Integer.negate(42)).toBe(-42) | ||
}) | ||
|
||
it('should return the negation of a number', () => { | ||
expect(Integer.negate(-42)).toBe(42) | ||
}) | ||
|
||
it('should return the negation of a number', () => { | ||
expect(Integer.negate(0)).toBe(0) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
import { Kind, Type, Number as Number_ } from '..' | ||
|
||
/** | ||
* `_$negate` is a type-level function that takes in an integer `T`, and | ||
* returns the integer negation of `T`. | ||
* | ||
* @template {number} T - An integer. | ||
* | ||
* @example | ||
* ```ts | ||
* import { Integer } from "hkt-toolbelt"; | ||
* | ||
* type Result = Integer._$negate<42>; // -42 | ||
* ``` | ||
*/ | ||
export type _$negate< | ||
T extends Number_.Number, | ||
NEG extends Number_.Number = Number_._$negate<T> | ||
> = NEG | ||
|
||
/** | ||
* `Negate` is a type-level function that takes in an integer `T`, and | ||
* returns the integer negation of `T`. | ||
* | ||
* @template {number} T - An integer. | ||
* | ||
* @example | ||
* ```ts | ||
* import { $, Integer } from "hkt-toolbelt"; | ||
* | ||
* type Result = $<Integer.Negate, 42>; // -42 | ||
* ``` | ||
*/ | ||
export interface Negate extends Kind.Kind { | ||
f(x: Type._$cast<this[Kind._], Number_.Number>): _$negate<typeof x> | ||
} | ||
|
||
/** | ||
* Given an integer, return its negation. | ||
* | ||
* @param {number} x - The integer to negate. | ||
* | ||
* @example | ||
* ```ts | ||
* import { Integer } from "hkt-toolbelt"; | ||
* | ||
* const result = Integer.negate(42) | ||
* // ^? -42 | ||
* ``` | ||
*/ | ||
export const negate = ((x: Number_.Number) => | ||
Number(x) === 0 ? 0 : -Number(x)) as Kind._$reify<Negate> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import { $, Kind, Function, Test } from '..' | ||
|
||
type ApplyKind_Spec = [ | ||
/** | ||
* Can apply a kind to a value. | ||
*/ | ||
Test.Expect<$<$<Kind.ApplyKind, Function.Identity>, [1, 2, 3]>, [1, 2, 3]> | ||
] | ||
|
||
it('should apply a kind to a value', () => { | ||
expect(Kind.applyKind(Function.identity)([1, 2, 3])).toEqual([1, 2, 3]) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
import { $, Kind, Type, Function } from '..' | ||
|
||
/** | ||
* `_$applyKind` is a type-level function that takes in a kind `K` and a value `X`, | ||
* and applies the kind to the value. | ||
* | ||
* @template K - The kind to apply | ||
* @template X - The value to apply K to | ||
* | ||
* @example | ||
* ```ts | ||
* import { Kind, Function } from "hkt-toolbelt"; | ||
* | ||
* type Result = Kind._$applyKind<Function.Identity, [1, 2, 3]>; // [1, 2, 3] | ||
* ``` | ||
*/ | ||
export type _$applyKind<K extends Kind.Kind, X> = $< | ||
K, | ||
Type._$cast<X, Kind._$inputOf<K>> | ||
> | ||
|
||
interface ApplyKind_T<K extends Kind.Kind> extends Kind.Kind { | ||
f(x: Type._$cast<this[Kind._], Kind._$inputOf<K>>): _$applyKind<K, typeof x> | ||
} | ||
|
||
/** | ||
* `ApplyKind` is a type-level function that takes in a kind `K` and a value `X`, | ||
* and applies the kind to the value. | ||
* | ||
* @template K - The kind to apply | ||
* @template X - The value to apply K to | ||
* | ||
* @example | ||
* ```ts | ||
* import { $, Kind, Function } from "hkt-toolbelt"; | ||
* | ||
* type Result = $<$<Kind.ApplyKind, Function.Identity>, [1, 2, 3]>; // [1, 2, 3] | ||
* // Equivalent to $<Function.Identity, [1, 2, 3]> | ||
* ``` | ||
*/ | ||
export interface ApplyKind extends Kind.Kind { | ||
f(x: Type._$cast<this[Kind._], Kind.Kind>): ApplyKind_T<typeof x> | ||
} | ||
|
||
/** | ||
* Given a kind and a value, apply the kind to the value. | ||
* | ||
* @param {Kind.Kind} k - The kind to apply. | ||
* @param {unknown} x - The value to apply the kind to. | ||
* | ||
* @example | ||
* ```ts | ||
* import { Kind, Function } from "hkt-toolbelt"; | ||
* | ||
* const result = Kind.applyKind(Function.identity)([1, 2, 3]) | ||
* // ^? [1, 2, 3] | ||
* ``` | ||
*/ | ||
export const applyKind = ((k: Function.Function) => (x: unknown) => | ||
k(x as never)) as Kind._$reify<ApplyKind> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
import { $, List, Test } from '..' | ||
|
||
type CartesianProduct_Spec = [ | ||
// Single element, single value | ||
Test.Expect<$<List.CartesianProduct, ['foo']>, [['foo']]>, | ||
|
||
// Two elements, both single values | ||
Test.Expect<$<List.CartesianProduct, ['foo', 'bar']>, [['foo', 'bar']]>, | ||
|
||
// Mix single and tuple | ||
Test.Expect< | ||
$<List.CartesianProduct, ['foo', ['bar', 'qux']]>, | ||
[['foo', 'bar'], ['foo', 'qux']] | ||
>, | ||
|
||
// Multiple tuples | ||
Test.Expect< | ||
$<List.CartesianProduct, [['a', 'b'], ['c', 'd']]>, | ||
[['a', 'c'], ['a', 'd'], ['b', 'c'], ['b', 'd']] | ||
>, | ||
|
||
// More complex example | ||
Test.Expect< | ||
$<List.CartesianProduct, [['x'], ['y', 'z'], [1, 2]]>, | ||
[['x', 'y', 1], ['x', 'y', 2], ['x', 'z', 1], ['x', 'z', 2]] | ||
> | ||
] | ||
|
||
describe('List.cartesianProduct (runtime)', () => { | ||
it('returns [[]] for an empty input', () => { | ||
expect(List.cartesianProduct([])).toEqual([[]]) | ||
}) | ||
|
||
it('handles a single element that is not an array', () => { | ||
expect(List.cartesianProduct(['foo'])).toEqual([['foo']]) | ||
}) | ||
|
||
it('handles multiple single-value elements', () => { | ||
// ["foo", "bar"] -> [["foo","bar"]] | ||
expect(List.cartesianProduct(['foo', 'bar'])).toEqual([['foo', 'bar']]) | ||
}) | ||
|
||
it('handles a mix of single values and arrays', () => { | ||
// ["foo", ["bar","qux"]] | ||
// Expect: [["foo","bar"],["foo","qux"]] | ||
const result = List.cartesianProduct(['foo', ['bar', 'qux']]) | ||
expect(result).toEqual([ | ||
['foo', 'bar'], | ||
['foo', 'qux'] | ||
]) | ||
}) | ||
|
||
it('handles multiple arrays', () => { | ||
// [["a","b"], ["c","d"]] | ||
// Expect: [["a","c"],["a","d"],["b","c"],["b","d"]] | ||
const result = List.cartesianProduct([ | ||
['a', 'b'], | ||
['c', 'd'] | ||
]) | ||
expect(result).toEqual([ | ||
['a', 'c'], | ||
['a', 'd'], | ||
['b', 'c'], | ||
['b', 'd'] | ||
]) | ||
}) | ||
|
||
it('handles more complex examples', () => { | ||
// [["x"], ["y","z"], [1,2]] | ||
// Expect: [ | ||
// ["x","y",1], | ||
// ["x","y",2], | ||
// ["x","z",1], | ||
// ["x","z",2] | ||
// ] | ||
const result = List.cartesianProduct([['x'], ['y', 'z'], [1, 2]]) | ||
expect(result).toEqual([ | ||
['x', 'y', 1], | ||
['x', 'y', 2], | ||
['x', 'z', 1], | ||
['x', 'z', 2] | ||
]) | ||
}) | ||
|
||
it('maintains order correctly', () => { | ||
// Order verification: | ||
// For [["a","b"], ["c","d"]], we specifically want [["a","c"],["a","d"],["b","c"],["b","d"]] | ||
const result = List.cartesianProduct([ | ||
['a', 'b'], | ||
['c', 'd'] | ||
]) | ||
expect(result).toEqual([ | ||
['a', 'c'], | ||
['a', 'd'], | ||
['b', 'c'], | ||
['b', 'd'] | ||
]) | ||
}) | ||
}) |
Oops, something went wrong.