-
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 pull request #94 from poteat/poteat/additional-reifications
Poteat/additional reifications
- Loading branch information
Showing
39 changed files
with
1,466 additions
and
22 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import { $, Combinator, Kind, Test } from '..' | ||
|
||
type Collapse_Spec = [ | ||
/** | ||
* Can collapse a kind. | ||
*/ | ||
Test.Expect<$<$<Kind.Collapse, $<Combinator.Collate, 2>>, 1>, [1, 1]> | ||
] | ||
|
||
it('should collapse a kind', () => { | ||
expect(Kind.collapse(Combinator.collate(2))(1)).toEqual([1, 1]) | ||
}) |
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,71 @@ | ||
import { $, Function, Kind, Type } from '..' | ||
|
||
/** | ||
* `_$collapse` is a type-level function that takes in a kind `K` and a value | ||
* `X`, and repeatedly applies the current function to the value until it no | ||
* longer returns a kind. | ||
* | ||
* @template {Kind.Kind} K - The kind to collapse. | ||
* @template {unknown} X - The value to collapse with. | ||
* | ||
* @example | ||
* ```ts | ||
* import { $, Kind, Combinator } from "hkt-toolbelt"; | ||
* | ||
* type T0 = _$collapse<$<Combinator.Collate, 2>, 1> // [2, 2] | ||
* ``` | ||
*/ | ||
export type _$collapse<K extends Kind.Kind, X extends Kind._$inputOf<K>> = | ||
$<K, X> extends infer NewValue | ||
? NewValue extends Kind.Kind | ||
? _$collapse<NewValue, Type._$cast<X, Kind._$inputOf<NewValue>>> | ||
: NewValue | ||
: never | ||
|
||
interface Collapse_T<K extends Kind.Kind> extends Kind.Kind { | ||
f(x: Type._$cast<this[Kind._], Kind._$inputOf<K>>): _$collapse<K, typeof x> | ||
} | ||
|
||
/** | ||
* `Collapse` is a type-level function that takes in a kind `K` and a value | ||
* `X`, and repeatedly applies the current function to the value until it no | ||
* longer returns a kind. | ||
* | ||
* @template {Kind.Kind} K - The kind to collapse. | ||
* @template {unknown} X - The value to collapse with. | ||
* | ||
* @example | ||
* ```ts | ||
* import { $, Kind, Combinator } from "hkt-toolbelt"; | ||
* | ||
* type T0 = $<$<Kind.Collapse, $<Combinator.Collate, 2>>, 1> // [2, 2] | ||
* ``` | ||
*/ | ||
export interface Collapse extends Kind.Kind { | ||
f(x: Type._$cast<this[Kind._], Kind.Kind>): Collapse_T<typeof x> | ||
} | ||
|
||
/** | ||
* Given a kind `K` and a value `X`, repeatedly apply the current function to | ||
* the value until it no longer returns a kind. | ||
* | ||
* @param {Kind.Kind} k - The kind to collapse. | ||
* @param {unknown} x - The value to collapse with. | ||
* | ||
* @example | ||
* ```ts | ||
* import { Kind, Combinator } from "hkt-toolbelt"; | ||
* | ||
* const result = Kind.collapse(Combinator.collate(2))(1) | ||
* // ^? [1, 1] | ||
* ``` | ||
*/ | ||
export const collapse = ((k: Function.Function) => (x: unknown) => { | ||
let f = k | ||
|
||
while (typeof f === 'function') { | ||
f = f(x as never) as Function.Function | ||
} | ||
|
||
return f | ||
}) as unknown as Kind._$reify<Collapse> |
This file was deleted.
Oops, something went wrong.
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,15 @@ | ||
import { Test, $N, Kind, Function, List } from '..' | ||
|
||
type Curry_Spec = [ | ||
Test.Expect< | ||
$N<Kind.Curry, [2, Function.Identity, 'foo', 'bar']>, | ||
['foo', 'bar'] | ||
> | ||
] | ||
|
||
it('should curry a function', () => { | ||
const myFcn = Kind.curry(2)(List.same) | ||
|
||
expect(myFcn('foo')('bar')).toBe(false) | ||
expect(myFcn('foo')('foo')).toBe(true) | ||
}) |
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,65 @@ | ||
import { $, Test, List } from '..' | ||
|
||
type Count_Spec = [ | ||
/** | ||
* Can count the number of occurrences of each key in a list. | ||
*/ | ||
Test.Expect< | ||
$<List.Count, ['foo', 'foo', 'bar']>, | ||
{ | ||
foo: 2 | ||
bar: 1 | ||
} | ||
>, | ||
|
||
/** | ||
* Can count the number of occurrences of each key in a list. | ||
*/ | ||
Test.Expect< | ||
$<List.Count, ['foo', 'foo', 'bar', 'baz']>, | ||
{ | ||
foo: 2 | ||
bar: 1 | ||
baz: 1 | ||
} | ||
>, | ||
|
||
/** | ||
* Counting an empty list results in an empty map. | ||
*/ | ||
Test.Expect<$<List.Count, []>, {}>, | ||
|
||
/** | ||
* Counting a list with a single element results in a map with one entry. | ||
*/ | ||
Test.Expect<$<List.Count, ['foo']>, { foo: 1 }>, | ||
|
||
/** | ||
* Counting a list of non-property keys results in a type error. | ||
*/ | ||
// @ts-expect-error | ||
Test.Expect<$<List.Count, ['foo', { foo: 'foo' }]>> | ||
] | ||
|
||
it('should count the number of occurrences of each key in a list', () => { | ||
expect(List.count(['foo', 'foo', 'bar'])).toEqual({ | ||
foo: 2, | ||
bar: 1 | ||
}) | ||
}) | ||
|
||
it('should count the number of occurrences of each key in a list', () => { | ||
expect(List.count(['foo', 'foo', 'bar', 'baz'])).toEqual({ | ||
foo: 2, | ||
bar: 1, | ||
baz: 1 | ||
}) | ||
}) | ||
|
||
it('should count an empty list as an empty map', () => { | ||
expect(List.count([])).toEqual({}) | ||
}) | ||
|
||
it('should count a list with a single element as a map with one entry', () => { | ||
expect(List.count(['foo'])).toEqual({ foo: 1 }) | ||
}) |
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,89 @@ | ||
import { NaturalNumber, Object, List, Kind, Type } from '..' | ||
|
||
type _$count2< | ||
T extends unknown[], | ||
O extends Record<string | number | symbol, number> = {} | ||
> = T extends [infer Head, ...infer Tail] | ||
? _$count2< | ||
Tail, | ||
Head extends PropertyKey | ||
? Object._$assign< | ||
Head, | ||
Head extends keyof O ? NaturalNumber._$increment<O[Head]> : 1, | ||
O | ||
> | ||
: never | ||
> | ||
: O | ||
|
||
/** | ||
* `_$count` is a type-level function that takes in a list of property keys and | ||
* returns a map from each key to the number of times it appears in the list. | ||
* | ||
* Similar to `List._$countBy`, but uses the identity function as the counting | ||
* function. | ||
* | ||
* @template {PropertyKey[]} K - The list of property keys to count. | ||
* | ||
* @example | ||
* ```ts | ||
* type T0 = _$count<['foo', 'foo', 'bar']> // { foo: 2, bar: 1 } | ||
* ``` | ||
*/ | ||
export type _$count<K extends PropertyKey[]> = | ||
List._$isVariadic<K> extends true | ||
? Record<K[number], number> | ||
: Type._$display<_$count2<K>> | ||
|
||
/** | ||
* `Count` is a type-level function that takes in a list of property keys and | ||
* returns a map from each key to the number of times it appears in the list. | ||
* | ||
* Similar to `List.CountBy`, but uses the identity function as the counting | ||
* function. | ||
* | ||
* @template {PropertyKey[]} K - The list of property keys to count. | ||
* | ||
* @example | ||
* ```ts | ||
* type T0 = $<$<List.Count, ['foo', 'foo', 'bar']> // { foo: 2, bar: 1 } | ||
* ``` | ||
*/ | ||
export interface Count extends Kind.Kind { | ||
f(x: Type._$cast<this[Kind._], PropertyKey[]>): _$count<typeof x> | ||
} | ||
|
||
/** | ||
* Given a list of property keys, return a map from each key to the number of | ||
* times it appears in the list. | ||
* | ||
* Similar to `List.CountBy`, but uses the identity function as the counting | ||
* function. | ||
* | ||
* @param {PropertyKey[]} k - The list of property keys to count. | ||
* | ||
* @example | ||
* ```ts | ||
* import { List } from "hkt-toolbelt"; | ||
* | ||
* const result = List.count(['foo', 'foo', 'bar']) | ||
* // ^? { foo: 2, bar: 1 } | ||
* ``` | ||
*/ | ||
export const count = ((k: PropertyKey[]) => { | ||
const result = {} as Record<PropertyKey, number> | ||
|
||
for (const key of k) { | ||
if ( | ||
typeof key !== 'string' && | ||
typeof key !== 'number' && | ||
typeof key !== 'symbol' | ||
) { | ||
return Type.never | ||
} | ||
|
||
result[key] = key in result ? result[key] + 1 : 1 | ||
} | ||
|
||
return result | ||
}) as Kind._$reify<Count> |
Oops, something went wrong.