From f75d6101f99db261b73c3f70d8c6d97a5dc85a92 Mon Sep 17 00:00:00 2001 From: Harry Solovay Date: Fri, 28 Oct 2022 13:06:03 -0400 Subject: [PATCH] chore: get rid of `Name` and refactor (#13) --- Effect.ts | 44 ++++++++++++++++------------------ Process.ts | 33 +++++++++++-------------- Runtime.ts | 4 ++-- core/derive.ts | 30 ----------------------- core/sel.ts | 20 ---------------- {core => effects}/call.ts | 0 effects/derive.ts | 22 +++++++++++++++++ {core => effects}/each.ts | 7 ++---- {core => effects}/if.ts | 6 ++--- {core => effects}/ls.ts | 0 {core => effects}/mod.ts | 1 - {core => effects}/rc.ts | 0 {core => effects}/rec.ts | 0 {core => effects}/try.ts | 11 ++++----- {core => effects}/wrap.ts | 0 examples/{sel.ts => access.ts} | 2 +- examples/derived.ts | 6 ++--- mod.ts | 2 +- util/common.ts | 1 + util/id.ts | 4 ++-- 20 files changed, 76 insertions(+), 117 deletions(-) delete mode 100644 core/derive.ts delete mode 100644 core/sel.ts rename {core => effects}/call.ts (100%) create mode 100644 effects/derive.ts rename {core => effects}/each.ts (62%) rename {core => effects}/if.ts (77%) rename {core => effects}/ls.ts (100%) rename {core => effects}/mod.ts (88%) rename {core => effects}/rc.ts (100%) rename {core => effects}/rec.ts (100%) rename {core => effects}/try.ts (74%) rename {core => effects}/wrap.ts (100%) rename examples/{sel.ts => access.ts} (87%) diff --git a/Effect.ts b/Effect.ts index 2e68759..57b49cb 100644 --- a/Effect.ts +++ b/Effect.ts @@ -24,36 +24,34 @@ export class Effect< ) { this.id = `${this.kind}(${this.children?.map(U.id.of).join(",") || ""})`; } + + access = >( + key: K, + ): Effect], E, V> => { + return new Effect("Access", (process) => { + return U.memo(() => { + return U.thenOk( + U.all(process.resolve(this), process.resolve(key)), + ([target, key]) => target[key], + ); + }); + }, [this, key]); + }; + + as = () => { + return this as unknown as Effect; + }; } // TODO: make generic? export type EffectInitRun = (process: Process) => () => unknown; -export abstract class Name { - abstract root: Root; - - get id(): string { - return this.root.id; - } -} - -export type EffectLike< - T = any, - E extends Error = Error, - V extends PropertyKey = PropertyKey, -> = Effect | Name>; - -export function isEffectLike(inQuestion: unknown): inQuestion is EffectLike { - return inQuestion instanceof Effect || inQuestion instanceof Name; -} - -// TODO: fully ensure no promises-wrappers/errors -export type T = U extends EffectLike ? T +export type T = U extends Effect ? T : U extends Placeholder ? T : Exclude, Error>; -export type E = U extends EffectLike ? E : never; -export type V = U extends EffectLike ? V +export type E = U extends Effect ? E : never; +export type V = U extends Effect ? V : U extends Placeholder ? U["key"] : never; -export type $ = T | EffectLike | Placeholder; +export type $ = T | Effect | Placeholder; diff --git a/Process.ts b/Process.ts index b652ad5..4ff2fae 100644 --- a/Process.ts +++ b/Process.ts @@ -1,4 +1,4 @@ -import { EffectLike, isEffectLike, Name } from "./Effect.ts"; +import { Effect } from "./Effect.ts"; import { isPlaceholder } from "./Placeholder.ts"; export class Process extends Map unknown> { @@ -8,35 +8,30 @@ export class Process extends Map unknown> { super(); } - init = (root: EffectLike) => { - const stack: EffectLike[] = [root]; + init = (root: Effect) => { + const stack: Effect[] = [root]; while (stack.length) { const currentSource = stack.pop()!; - if (currentSource instanceof Name) { - stack.push(currentSource.root); - continue; - } else { - let run = this.get(currentSource.id); - if (!run) { - run = currentSource.run(this); - this.set(currentSource.id, run); - currentSource.children?.forEach((arg) => { - if (isEffectLike(arg)) { - stack.push(arg); - } - }); - } + let run = this.get(currentSource.id); + if (!run) { + run = currentSource.run(this); + this.set(currentSource.id, run); + currentSource.children?.forEach((arg) => { + if (arg instanceof Effect) { + stack.push(arg); + } + }); } } return this.get(root.id)!; }; - run = (effect: EffectLike) => { + run = (effect: Effect) => { return this.get(effect.id)!; }; resolve = (x: unknown) => { - return isEffectLike(x) + return x instanceof Effect ? this.run(x)!() : isPlaceholder(x) ? this.applies[x.key] diff --git a/Runtime.ts b/Runtime.ts index 094f811..6a971d6 100644 --- a/Runtime.ts +++ b/Runtime.ts @@ -1,4 +1,4 @@ -import { E, EffectLike, T, V } from "./Effect.ts"; +import { E, Effect, T, V } from "./Effect.ts"; import { UntypedError } from "./Error.ts"; import { EnsureSoleApplies, flattenApplies } from "./Placeholder.ts"; import { Process } from "./Process.ts"; @@ -17,7 +17,7 @@ export function runtime[]>( } export interface Runtime { - ( + ( root: Root, ...[apply]: [Exclude, Applies>] extends [never] ? [] : [useApplies: UseApplies, Applies>] diff --git a/core/derive.ts b/core/derive.ts deleted file mode 100644 index 58d4c84..0000000 --- a/core/derive.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { E, Effect, EffectLike, T, V } from "../Effect.ts"; -import { thrownAsUntypedError } from "../Error.ts"; -import * as U from "../util/mod.ts"; - -export function derive( - from: Target, - into: DeriveInto, -): Effect< - T>, - | E - | Extract, Error> - | E, EffectLike>>, - V | V> -> { - const e = new Effect("Derive", (process) => { - return (): unknown => { - return U.thenOk( - U.then(process.resolve(from), thrownAsUntypedError(e, into)), - (e) => process.init(e)(), - ); - }; - }, [from, into]); - return e as any; -} - -export type DeriveResult = Error | EffectLike | Promise; - -export type DeriveInto = ( - resolved: T, -) => UseR; diff --git a/core/sel.ts b/core/sel.ts deleted file mode 100644 index b557351..0000000 --- a/core/sel.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { $, E, Effect, T, V } from "../Effect.ts"; -import * as U from "../util/mod.ts"; - -export function sel, Key extends $>>( - target: Target, - key: Key, -): Effect< - T[T extends keyof T ? T : never], - E, - V -> { - return new Effect("Sel", (process) => { - return U.memo(() => { - return U.thenOk( - U.all(process.resolve(target), process.resolve(key)), - ([target, key]) => target[key], - ); - }); - }, [target, key]); -} diff --git a/core/call.ts b/effects/call.ts similarity index 100% rename from core/call.ts rename to effects/call.ts diff --git a/effects/derive.ts b/effects/derive.ts new file mode 100644 index 0000000..2432bd5 --- /dev/null +++ b/effects/derive.ts @@ -0,0 +1,22 @@ +import { E, Effect, T, V } from "../Effect.ts"; +import { thrownAsUntypedError } from "../Error.ts"; +import * as U from "../util/mod.ts"; + +export function derive( + from: From, + into: DeriveInto, +): Effect, E, V> { + const e = new Effect("Derive", (process) => { + return (): unknown => { + return U.thenOk( + U.then(process.resolve(from), thrownAsUntypedError(e, into)), + (e) => process.init(e)(), + ); + }; + }, [from, into]); + return e as any; +} + +export type DeriveInto = ( + resolved: T, +) => IntoR; diff --git a/core/each.ts b/effects/each.ts similarity index 62% rename from core/each.ts rename to effects/each.ts index 28ea834..15a035a 100644 --- a/core/each.ts +++ b/effects/each.ts @@ -1,11 +1,8 @@ -import { $, EffectLike, T } from "../Effect.ts"; +import { $, Effect, T } from "../Effect.ts"; import { derive } from "./derive.ts"; import { ls } from "./ls.ts"; -export function each< - Elements extends $, - Into extends EffectLike, ->( +export function each, Into extends Effect>( elements: Elements, cb: (element: T[number]) => Into, ) { diff --git a/core/if.ts b/effects/if.ts similarity index 77% rename from core/if.ts rename to effects/if.ts index 9f0756c..f7d10a9 100644 --- a/core/if.ts +++ b/effects/if.ts @@ -1,10 +1,10 @@ -import { $, EffectLike } from "../Effect.ts"; +import { $, Effect } from "../Effect.ts"; import { derive } from "./derive.ts"; function if_< Condition extends $, - Then extends EffectLike, - Else extends EffectLike, + Then extends Effect, + Else extends Effect, >( condition: Condition, then: Then, diff --git a/core/ls.ts b/effects/ls.ts similarity index 100% rename from core/ls.ts rename to effects/ls.ts diff --git a/core/mod.ts b/effects/mod.ts similarity index 88% rename from core/mod.ts rename to effects/mod.ts index 1e94db5..1b3ccc0 100644 --- a/core/mod.ts +++ b/effects/mod.ts @@ -4,6 +4,5 @@ export * from "./if.ts"; export * from "./ls.ts"; export * from "./rc.ts"; export * from "./rec.ts"; -export * from "./sel.ts"; export * from "./try.ts"; export * from "./wrap.ts"; diff --git a/core/rc.ts b/effects/rc.ts similarity index 100% rename from core/rc.ts rename to effects/rc.ts diff --git a/core/rec.ts b/effects/rec.ts similarity index 100% rename from core/rec.ts rename to effects/rec.ts diff --git a/core/try.ts b/effects/try.ts similarity index 74% rename from core/try.ts rename to effects/try.ts index a064dc5..37d2dd8 100644 --- a/core/try.ts +++ b/effects/try.ts @@ -1,9 +1,9 @@ -import { E, Effect, EffectLike, T, V } from "../Effect.ts"; +import { E, Effect, T, V } from "../Effect.ts"; import * as U from "../util/mod.ts"; // TODO: fix this export function try_< - Attempt extends EffectLike, + Attempt extends Effect, FallbackR extends T | Error, >( attempt: Attempt, @@ -25,7 +25,6 @@ Object.defineProperty(try_, "name", { }); export { try_ as try }; -export type Catch< - Target extends EffectLike, - CatchR, -> = (attemptError: E) => CatchR; +export type Catch = ( + attemptError: E, +) => CatchR; diff --git a/core/wrap.ts b/effects/wrap.ts similarity index 100% rename from core/wrap.ts rename to effects/wrap.ts diff --git a/examples/sel.ts b/examples/access.ts similarity index 87% rename from examples/sel.ts rename to examples/access.ts index eea01e4..93eb786 100644 --- a/examples/sel.ts +++ b/examples/access.ts @@ -8,7 +8,7 @@ const x = Z.call(0, () => { } as const; }); -const y = Z.sel(x, "b"); +const y = x.access("b"); const result = Z.runtime()(y); diff --git a/examples/derived.ts b/examples/derived.ts index 6f8f944..9f51822 100644 --- a/examples/derived.ts +++ b/examples/derived.ts @@ -1,4 +1,4 @@ -import { derive } from "../core/derive.ts"; +import { derive } from "../effects/derive.ts"; import * as Z from "../mod.ts"; const coinToss = Z.call(0, () => { @@ -6,9 +6,7 @@ const coinToss = Z.call(0, () => { }); const root = derive(coinToss, (truth) => { - return truth - ? Z.call(undefined!, () => "HELLO") - : Z.call(undefined!, () => "GOODBYE"); + return Z.call(undefined!, () => truth ? "HELLO" : "GOODBYE"); }); const result = await Z.runtime()(root); diff --git a/mod.ts b/mod.ts index 4217ba6..2fc3d60 100644 --- a/mod.ts +++ b/mod.ts @@ -1,5 +1,5 @@ -export * from "./core/mod.ts"; export * from "./Effect.ts"; +export * from "./effects/mod.ts"; export * from "./Error.ts"; export * from "./Placeholder.ts"; export * from "./Process.ts"; diff --git a/util/common.ts b/util/common.ts index 679d47a..e5858ac 100644 --- a/util/common.ts +++ b/util/common.ts @@ -8,6 +8,7 @@ export type U2I = (T extends any ? (value: T) => any : never) extends (value: infer R) => any ? R : never; export type AssertIsO = T extends Record ? T : never; +export type AssertKeyof = K extends keyof T ? K : never; // TODO: delete if unused export type ValueOf = T[keyof T]; diff --git a/util/id.ts b/util/id.ts index f23e2db..fa14030 100644 --- a/util/id.ts +++ b/util/id.ts @@ -1,4 +1,4 @@ -import { isEffectLike } from "../Effect.ts"; +import { Effect } from "../Effect.ts"; import * as U from "../util/mod.ts"; class IdFactory { @@ -32,7 +32,7 @@ export function of(target: unknown): string { return `fn(${target.name})`; } case "object": { - if (isEffectLike(target)) { + if (target instanceof Effect) { return target.id; } else if (target === null) { return "null";