Skip to content

Commit

Permalink
try new core idea
Browse files Browse the repository at this point in the history
  • Loading branch information
gvergnaud committed Jul 15, 2023
1 parent 3455aa2 commit fc217da
Show file tree
Hide file tree
Showing 3 changed files with 151 additions and 4 deletions.
8 changes: 4 additions & 4 deletions src/internals/core/Core.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { ExcludePlaceholders, MergeArgs } from "./impl/MergeArgs";
import { Head } from "../helpers";

declare const rawArgs: unique symbol;
type rawArgs = typeof rawArgs;
export declare const rawArgs: unique symbol;
export type rawArgs = typeof rawArgs;

/**
* Base interface for all functions.
Expand Down Expand Up @@ -36,8 +36,8 @@ export interface Fn {
return: unknown;
}

declare const unset: unique symbol;
declare const _: unique symbol;
export declare const unset: unique symbol;
export declare const _: unique symbol;

/**
* A placeholder type that can be used to indicate that a parameter is not set.
Expand Down
138 changes: 138 additions & 0 deletions src/internals/core/Core2.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
import { _, unset } from "./Core";
import { ExcludePlaceholders, ExcludeUnset, MergeArgs } from "./impl/MergeArgs";
import * as NumberImpl from "../numbers/impl/numbers";

/**
* Core
*/

export interface Fn<input extends any[] = unknown[]> {
inputTypes: input;
args: unknown;
return: unknown;
}

interface Ap<fn extends Fn, partialArgs extends any[] = []> extends Fn {
name: "Ap";

inputTypes: fn["inputTypes"];

argsArray: Extract<this["args"], any[]>;
allArgs: [...partialArgs, ...this["argsArray"]];

expectedArgsCount: fn["inputTypes"]["length"];
providedArgsCount: ExcludePlaceholders<this["allArgs"]>["length"];

return: NumberImpl.Compare<
this["providedArgsCount"],
this["expectedArgsCount"]
> extends 1 | 0
? Apply<fn, MergeArgs<this["argsArray"], partialArgs>>
: Ap<fn, this["allArgs"]>;
}

export type Apply<fn extends Fn, args extends any[]> = (fn & {
args: args;
})["return"];

export type $<
fn extends Fn,
arg0 extends fn["inputTypes"][0] | _ | unset = unset,
arg1 extends fn["inputTypes"][1] | _ | unset = unset,
arg2 extends fn["inputTypes"][2] | _ | unset = unset,
arg3 extends fn["inputTypes"][3] | _ | unset = unset
> = ((fn extends { name: "Ap" } ? fn : Ap<fn>) & {
args: ExcludeUnset<[arg0, arg1, arg2, arg3]>;
})["return"];

type Args<fn extends Fn> = Extract<fn["args"], fn["inputTypes"]>;
type Arg0<fn extends Fn> = Extract<fn["args"], fn["inputTypes"]>[0];
type Arg1<fn extends Fn> = Extract<fn["args"], fn["inputTypes"]>[1];
type Arg2<fn extends Fn> = Extract<fn["args"], fn["inputTypes"]>[2];
type Arg3<fn extends Fn> = Extract<fn["args"], fn["inputTypes"]>[3];

type ExpectNumber<a extends number> = [a];
// arguments are typed internally:
interface TypedArgsTest extends Fn<[number, string]> {
works: ExpectNumber<Arg0<this>>; // ✅
fails: ExpectNumber<Arg1<this>>;
// ~~~~~~~~~~ ❌
return: true;
}

interface Div extends Fn<[number, number]> {
return: NumberImpl.Div<Arg0<this>, Arg1<this>>;
}

/**
* Full application
*/

type x = $<Div, 10, 2>; // 5
// ^?
type y = $<Div, "10", 2>;
// ~~~ ❌
type z = $<Div, 11, "2">;
// ~~~ ❌

/**
* Partial application in order
*/

type Div1 = $<Div, 10>;
type Three = $<Div1, 2>;
// ^?
type w = $<$<Div, 10>, "2">;
// ~~~ ❌

/**
* Partial application different order order
*/
type DivBy2 = $<Div, _, 2>;
// ^?
type q = $<DivBy2, 10>; // 5 ✅
// ^?
type r = $<$<Div, _>, 10, 5>; // ✅
// ^?

/**
* Higher order
*/

interface Map extends Fn<[Fn, any[]]> {
return: Args<this> extends [infer fn extends Fn, infer tuple]
? { [key in keyof tuple]: $<fn, tuple[key]> }
: never;
}

type z2 = $<Map, $<Div, _, 2>, [2, 4, 6, 8, 10]>;
// ^?

type ReduceImpl<fn extends Fn, acc, xs> = xs extends [
infer first,
...infer rest
]
? ReduceImpl<fn, $<fn, acc, first>, rest>
: acc;

interface Reduce extends Fn<[Fn, any, any[]]> {
return: Args<this> extends [infer fn extends Fn, infer acc, infer tuple]
? ReduceImpl<fn, acc, tuple>
: never;
}

interface Add extends Fn<[number, number]> {
return: NumberImpl.Add<Arg0<this>, Arg1<this>>;
}

interface Mul extends Fn<[number, number]> {
return: NumberImpl.Mul<Arg0<this>, Arg1<this>>;
}

type reduced1 = $<Reduce, Add, 0, [2, 4, 6, 8, 10]>;
// ^?
type reduced2 = $<Reduce, Mul, 1, [2, 4, 6, 8, 10]>;
// ^?

type reducedOops = $<Reduce, Mul, 1, "oops">;
// ~~~~~~ ❌
9 changes: 9 additions & 0 deletions src/internals/core/impl/MergeArgs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,15 @@ export type ExcludePlaceholders<xs, output extends any[] = []> = xs extends [
: ExcludePlaceholders<rest, [...output, first]>
: output;

export type ExcludeUnset<xs, output extends any[] = []> = xs extends [
infer first,
...infer rest
]
? Equal<first, unset> extends true
? ExcludeUnset<rest, output>
: ExcludeUnset<rest, [...output, first]>
: output;

type MergeArgsRec<
pipedArgs extends any[],
partialArgs extends any[],
Expand Down

0 comments on commit fc217da

Please sign in to comment.