From aab613030d6604f32c96e9d58b88f5e49ad94408 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Mon, 23 Mar 2026 19:40:00 +0100 Subject: [PATCH] Fix --- packages/effect-fc/src/Lens.ts | 94 ++++++++++++++++++---------------- 1 file changed, 51 insertions(+), 43 deletions(-) diff --git a/packages/effect-fc/src/Lens.ts b/packages/effect-fc/src/Lens.ts index 98d16b7..18d10b3 100644 --- a/packages/effect-fc/src/Lens.ts +++ b/packages/effect-fc/src/Lens.ts @@ -1,4 +1,4 @@ -import { Effect, Pipeable, Predicate, Readable, Stream, Subscribable, SubscriptionRef } from "effect" +import { Effect, Pipeable, Predicate, Readable, Stream, Subscribable, type SubscriptionRef } from "effect" export const LensTypeId: unique symbol = Symbol.for("@effect-fc/Lens/Lens") @@ -8,7 +8,6 @@ export interface Lens { readonly [LensTypeId]: LensTypeId - readonly set: (a: A) => Effect.Effect readonly modify: ( f: (a: A) => Effect.Effect ) => Effect.Effect @@ -23,30 +22,42 @@ extends Pipeable.Class() implements Lens { constructor( readonly get: Effect.Effect, readonly changes: Stream.Stream, - readonly set: (a: A) => Effect.Effect, + readonly modify: ( + f: (a: A) => Effect.Effect + ) => Effect.Effect, ) { super() } - - modify( - f: (a: A) => Effect.Effect - ) { - return Effect.flatMap( - this.get, - a => Effect.flatMap(f(a), ([b, next]) => Effect.as(this.set(next), b) - )) - } } export const isLens = (u: unknown): u is Lens => Predicate.hasProperty(u, LensTypeId) -export const make = (options: { - readonly get: Effect.Effect - readonly changes: Stream.Stream - readonly set: (a: A) => Effect.Effect -}): Lens => new LensImpl(options.get, options.changes, options.set) +export const make = ( + options: { + readonly get: Effect.Effect + readonly changes: Stream.Stream + } & ( + | { + readonly modify: ( + f: (a: A) => Effect.Effect + ) => Effect.Effect + } + | { readonly set: (a: A) => Effect.Effect } + ) +): Lens => new LensImpl( + options.get, + options.changes, + Predicate.hasProperty(options, "modify") + ? options.modify + : ( + f: (a: A) => Effect.Effect + ) => Effect.flatMap( + options.get, + a => Effect.flatMap(f(a), ([b, next]) => Effect.as(options.set(next), b) + )), +) /** * Creates a `Lens` that directly proxies a `SubscriptionRef`. @@ -56,52 +67,47 @@ export const fromSubscriptionRef = ( ): Lens => make({ get: ref.get, get changes() { return ref.changes }, - set: a => SubscriptionRef.set(ref, a), + modify: ref.modifyEffect, }) export const map = ( self: Lens, get: (a: A) => B, - set: (b: B) => A, + set: (b: B, parent: A) => A, ): Lens => { - make({ - get: Effect.map(self.get, get), - changes: Stream.map(self.changes, get), - - }) - const get = Effect.map(self.get, f) - const changes = Stream.map(self.changes, f) - const set = (b: B) => self.set(g(b)) - - const out = new LensImpl(get, changes, set) - - ;(out as any).modify = ( + const getEffect = Effect.map(self.get, get) + const changes = Stream.map(self.changes, get) + const modify = ( h: (b: B) => Effect.Effect ) => self.modify((a: A) => { - const b = f(a) - return Effect.flatMap(h(b), ([c, bNext]) => Effect.succeed([c, g(bNext)] as const)) + const b = get(a) + return Effect.flatMap(h(b), ([c, bNext]) => Effect.succeed([c, set(bNext, a)] as const)) }) - return out + return make({ + get: getEffect, + changes, + modify, + }) } export const mapEffect = ( self: Lens, getF: (a: A) => Effect.Effect, - setF: (b: B) => Effect.Effect, + setF: (b: B, parent: A) => Effect.Effect, ): Lens => { const get = Effect.flatMap(self.get, getF) const changes = Stream.mapEffect(self.changes, getF) - const set = (b: B) => Effect.flatMap(setF(b), a => self.set(a)) - - const out = new LensImpl(get, changes, set) - - ;(out as any).modify = ( + const modify = ( h: (b: B) => Effect.Effect - ) => self.modify((a: A) => Effect.flatMap(getF(a), b => Effect.flatMap(h(b), ([c, bNext]) => Effect.flatMap(setF(bNext), nextA => Effect.succeed([c, nextA] as const))))) + ) => self.modify((a: A) => Effect.flatMap(getF(a), b => Effect.flatMap(h(b), ([c, bNext]) => Effect.flatMap(setF(bNext, a), nextA => Effect.succeed([c, nextA] as const))))) - return out + return make({ + get, + changes, + modify, + }) } export const unwrap = ( @@ -109,5 +115,7 @@ export const unwrap = ( ): Lens => make({ get: Effect.flatMap(effect, l => l.get), changes: Stream.unwrap(Effect.map(effect, l => l.changes)), - set: a => Effect.flatMap(effect, l => l.set(a)), + modify: ( + f: (a: A) => Effect.Effect + ) => Effect.flatMap(effect, l => l.modify(f)), })