diff --git a/packages/effect-lens/src/Lens.ts b/packages/effect-lens/src/Lens.ts index 0016c73..8b28408 100644 --- a/packages/effect-lens/src/Lens.ts +++ b/packages/effect-lens/src/Lens.ts @@ -29,7 +29,14 @@ export const isLens = (u: unknown): u is Lens { + readonly value: A + readonly commit: ( + next: Effect.Effect + ) => Effect.Effect +} export interface LensStep< in out A, @@ -44,9 +51,8 @@ export interface LensStep< in out RSW = never, > { readonly [LensStepTypeId]: LensStepTypeId - readonly transform: (effect: Effect.Effect) => Effect.Effect + readonly access: (effect: Effect.Effect, ESR, RSR>) => Effect.Effect, ER, RR> readonly transformStream: (stream: Stream.Stream) => Stream.Stream - readonly update: (next: Effect.Effect, parent: B) => Effect.Effect } export const isLensStep = (u: unknown): u is LensStep => Predicate.hasProperty(u, LensStepTypeId) @@ -89,11 +95,23 @@ extends Pipeable.Class() implements Lens { abstract readonly sourceCommit: (b: B) => Effect.Effect abstract readonly withLock: (self: Effect.Effect) => Effect.Effect - get get(): Effect.Effect { - let effect: Effect.Effect = this.sourceGet + private get access(): Effect.Effect, ER, RR> { + let effect: Effect.Effect, unknown, unknown> = Effect.map( + this.sourceGet, + value => ({ + value, + commit: next => Effect.flatMap(next, value => this.sourceCommit(value as B)), + }), + ) + for (const step of this.steps) - effect = step.transform(effect) - return effect as Effect.Effect + effect = step.access(effect as never) as Effect.Effect, unknown, unknown> + + return effect as Effect.Effect, ER, RR> + } + + get get(): Effect.Effect { + return Effect.map(this.access, frame => frame.value) } get changes(): Stream.Stream { @@ -107,38 +125,12 @@ extends Pipeable.Class() implements Lens { f: (a: A) => Effect.Effect, ): Effect.Effect { return this.withLock(Effect.flatMap( - this.sourceGet, - source => { - const parents: unknown[] = [] - let current: Effect.Effect = Effect.succeed(source) - - for (const step of this.steps) - current = Effect.flatMap(current, parent => { - parents.push(parent) - return step.transform(Effect.succeed(parent)) - }) - - return Effect.flatMap(current, a => Effect.flatMap( - f(a as A), - ([c, next]) => { - let rebuilt: Effect.Effect = Effect.succeed(next) - - for (let i = this.steps.length - 1; i >= 0; i--) { - // biome-ignore lint/style/noNonNullAssertion: won't throw - const step = this.steps[i]! - // biome-ignore lint/style/noNonNullAssertion: won't throw - const parent = parents[i]! - rebuilt = step.update(rebuilt, parent) - } - - return Effect.as( - Effect.flatMap(rebuilt, b => this.sourceCommit(b as B)), - c, - ) - }, - )) - }, - )) as Effect.Effect + this.access, + frame => Effect.flatMap( + f(frame.value), + ([c, next]) => Effect.as(frame.commit(Effect.succeed(next)), c), + ), + )) } }