Skip to content

Commit

Permalink
Merge pull request #55 from MajorLift/jongsun/util/230815-kind-apply-n
Browse files Browse the repository at this point in the history
Add Kind util `ApplyN`, and derived List methods
  • Loading branch information
MajorLift authored Dec 20, 2023
2 parents e075f6b + 29fe400 commit 5af1497
Show file tree
Hide file tree
Showing 13 changed files with 578 additions and 0 deletions.
114 changes: 114 additions & 0 deletions src/kind/apply-n.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import {
$,
$N,
Kind,
Function,
Conditional,
List,
String,
Test
} from 'hkt-toolbelt'

type ApplyN_Spec = [
/**
* Can apply kinds to types.
*/
Test.Expect<
$<$<Kind.ApplyN, [Function.Identity, [number]]>, List.Map>,
[number]
>,

/**
* Can apply never
*/
Test.Expect<$<$<Kind.ApplyN, [never]>, Function.Identity>, never>,
Test.Expect<
$<
$<Kind.ApplyN, [never]>,
$N<
Conditional.If,
[
$<Conditional.Extends, never>,
$<Function.Constant, true>,
$<Function.Constant, false>
]
>
>,
true
>,

/**
* Can be used in its partially applied form.
*/
Test.Expect<
$N<
List.Map,
[
$<
$<Kind.ApplyN, [$<Function.Constant, null>]>,
$N<Conditional.If, [$<Conditional.Equals, 1>, Function.Identity]>
>,
$<List.Times, 3>
]
>,
[null, 1, null]
>,

/**
* Can loop through a list of kinds and apply them to an input.
*/
Test.Expect<
$<
$<List.Map, $<Kind.ApplyN, ['qux']>>,
[$<String.Prepend, 'foo'>, $<String.Append, 'bar'>, String.ToUpper]
>,
['fooqux', 'quxbar', 'QUX']
>,

Test.Expect<
$N<
List.Map,
[
$<Kind.Apply, number | symbol>,
$N<
List.Map,
[
$<
Kind.ApplyN,
[$<Function.Constant, true>, $<Function.Constant, false>]
>,
[
$<Conditional.If, $<Conditional.Extends, never>>,
$<Conditional.If, $<Conditional.Extends, string>>,
$<Conditional.If, $<Conditional.Extends, number | symbol>>
]
]
>
]
>,
[false, false, true]
>,

Test.Expect<
$N<
List.Map,
[
$<$<Kind.ApplyN, [0, 1, ['new']]>, List.Splice>,
[['old', 1, 2], ['old', 3, 4]]
]
>,
[['new', 1, 2], ['new', 3, 4]]
>,

/**
* $ enforces list inputs.
*/
// @ts-expect-error
$<$<Kind.Apply, number>, String.StartsWith<'foo'>>,

/**
* $ will emit an error on non-kinds.
*/
// @ts-expect-error
$<$<Kind.Apply, [number]>, number>
]
57 changes: 57 additions & 0 deletions src/kind/arity.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { $, Kind, List, Test } from '..'

type Arity_Spec = [
/**
* Returns empty tuple for fully applied function
*/
Test.Expect<$<Kind.Arity, $<$<$<List.Reduce, never>, never>, never>>, 0>,

/**
* Returns tuple of length one for partially applied function expecting one more argument.
*/
Test.Expect<$<Kind.Arity, $<$<List.Reduce, never>, never>>, 1>,

/**
* Returns tuple of length two for partially applied function expecting two more arguments.
*/
Test.Expect<$<Kind.Arity, $<List.Reduce, never>>, 2>,

/**
* Returns tuple of length three for 3-ary function.
*/
Test.Expect<$<Kind.Arity, List.Reduce>, 3>,

/**
* Returns empty tuple for fully applied function
*/
Test.Expect<
$<Kind.Arity, $<$<$<$<List.Splice, never>, never>, never>, never>>,
0
>,

/**
* Returns tuple of length one for partially applied function expecting one more argument.
*/
Test.Expect<$<Kind.Arity, $<$<$<List.Splice, never>, never>, never>>, 1>,

/**
* Returns tuple of length two for partially applied function expecting two more arguments.
*/
Test.Expect<$<Kind.Arity, $<$<List.Splice, never>, never>>, 2>,

/**
* Returns tuple of length three for partially applied function expecting three more arguments.
*/
Test.Expect<$<Kind.Arity, $<List.Splice, never>>, 3>,

/**
* Returns tuple of length four for 4-ary function.
*/
Test.Expect<$<Kind.Arity, List.Splice>, 4>,

/**
* Emits error for non-kind input
*/
// @ts-expect-error
Test.Expect<$<Kind.Arity, number>, never>
]
40 changes: 40 additions & 0 deletions src/kind/arity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { $, Kind, Type, Number, NaturalNumber } from '..'

/**
* `_$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.
*
* @template {Kind.Kind} K - A type-level function whose arity will be returned.
* @returns {Number.Number} The number of arguments that `K` can be successively applied to.
*
* If `K` is a fully-applied `Kind`, 0 will be returned.
* If `K` is not a `Kind`, an error will be emitted.
*/
export type _$arity<
K extends Kind.Kind,
ACC extends Number.Number = 0
> = Kind._$inputOf<K> extends never
? ACC
: $<K, never> extends Kind.Kind
? _$arity<$<K, never>, NaturalNumber._$increment<ACC>>
: never

/**
* `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.
*
* @template {Kind.Kind} K - A type-level function whose arity will be returned.
* @returns {Number.Number} The number of arguments that `K` can be successively applied to.
*
* If `K` is a fully-applied `Kind`, 0 will be returned.
* If `K` is not a `Kind`, an error will be emitted.
*
* @example
* type ReduceArity = $<Kind.Arity, List.Reduce> // 3
* type PartialApply1 = $<Kind.Arity, $<List.Reduce, never>> // 2
* type PartialApply2 = $<Kind.Arity, $<$<List.Reduce, never>, never>> // 1
* type FullApply = $<Kind.Arity, $<$<$<List.Reduce, never>, never>, never>> // 0
*/
export interface Arity extends Kind.Kind {
f(x: Type._$cast<this[Kind._], Kind.Kind>): _$arity<typeof x>
}
3 changes: 3 additions & 0 deletions src/kind/index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
export * from './apply'
export * from './apply-n'
export * from './arity'
export * from './composable-pair'
export * from './composable'
export * from './compose'
export * from './curry'
export * from './input-of'
export * from './kind'
export * from './output-of'
export * from './parameters'
export * from './pipe'
export * from './reify'
export * from './unapply'
Expand Down
75 changes: 75 additions & 0 deletions src/kind/parameters.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { $, Kind, List, Number, Test } from '..'

type Parameters_Spec = [
/**
* Returns empty tuple for fully applied function
*/
Test.Expect<
$<Kind.Parameters, $<$<$<List.Reduce, never>, never>, never>>,
[]
>,

/**
* Returns tuple of length one for partially applied function expecting one more argument.
*/
Test.Expect<$<Kind.Parameters, $<$<List.Reduce, never>, never>>, [List.List]>,

/**
* Returns tuple of length two for partially applied function expecting two more arguments.
*/
Test.Expect<$<Kind.Parameters, $<List.Reduce, never>>, [unknown, List.List]>,

/**
* Returns tuple of length three for 3-ary function.
*/
Test.Expect<
$<Kind.Parameters, List.Reduce>,
[Kind.Kind<(x: never) => Kind.Kind>, unknown, List.List]
>,

/**
* Returns empty tuple for fully applied function
*/
Test.Expect<
$<Kind.Parameters, $<$<$<$<List.Splice, never>, never>, never>, never>>,
[]
>,

/**
* Returns tuple of length one for partially applied function expecting one more argument.
*/
Test.Expect<
$<Kind.Parameters, $<$<$<List.Splice, never>, never>, never>>,
[List.List]
>,

/**
* Returns tuple of length two for partially applied function expecting two more arguments.
*/
Test.Expect<
$<Kind.Parameters, $<$<List.Splice, never>, never>>,
[List.List, List.List]
>,

/**
* Returns tuple of length three for partially applied function expecting three more arguments.
*/
Test.Expect<
$<Kind.Parameters, $<List.Splice, never>>,
[Number.Number, List.List, List.List]
>,

/**
* Returns tuple of length four for 4-ary function.
*/
Test.Expect<
$<Kind.Parameters, List.Splice>,
[Number.Number, Number.Number, List.List, List.List]
>,

/**
* Emits error for non-kind input
*/
// @ts-expect-error
Test.Expect<$<Kind.Parameters, number>, never>
]
52 changes: 52 additions & 0 deletions src/kind/parameters.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { $, Kind, Type, List } from '..'

/**
* `_$parameters` is a type-level function that takes in a curried n-ary type-level function,
* and returns an ordered list of the types of the n arguments that the input function is expecting.
*
* @template {Kind.Kind} K - A type-level function whose parameters will be returned.
* @returns {List.List} A list of the types of the arguments that `K` can be successively applied to.
*
* `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.
*/
export type _$parameters<
K extends Kind.Kind,
ACC extends List.List = []
> = Kind._$inputOf<K> extends never
? ACC
: $<K, never> extends Kind.Kind
? _$parameters<$<K, never>, List._$push<Kind._$inputOf<K>, ACC>>
: never

/**
* `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.
*
* @template {Kind.Kind} K - A type-level function whose parameters will be returned.
* @returns {List.List} A list of the types of the arguments that `K` can be successively applied to.
*
* `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.
*
* @example
* type ReduceParams = $<Kind.Parameters, List.Reduce> // [Kind.Kind<(x: never) => Kind.Kind>, unknown, List.List]
* type PartialApply1 = $<Kind.Parameters, $<List.Reduce, never>> // [unknown, List.List]
* type PartialApply2 = $<Kind.Parameters, $<$<List.Reduce, never>, never>> // [List.List]
* type FullApply = $<Kind.Parameters, $<$<$<List.Reduce, never>, never>, never>> // []
*/
export interface Parameters extends Kind.Kind {
f(x: Type._$cast<this[Kind._], Kind.Kind>): _$parameters<typeof x>
}
3 changes: 3 additions & 0 deletions src/list/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,15 @@ export * from './filter'
export * from './find'
export * from './first'
export * from './includes'
export * from './inverse-map'
export * from './inverse-map-n'
export * from './iterate'
export * from './is-variadic'
export * from './last'
export * from './length'
export * from './list'
export * from './map'
export * from './map-n'
export * from './pair'
export * from './pop'
export * from './pop-n'
Expand Down
Loading

0 comments on commit 5af1497

Please sign in to comment.