Skip to content

Instantly share code, notes, and snippets.

@yanisurbis
Created September 25, 2023 07:31
Show Gist options
  • Save yanisurbis/3198cc6f15e26bd2161edefef74e565b to your computer and use it in GitHub Desktop.
Save yanisurbis/3198cc6f15e26bd2161edefef74e565b to your computer and use it in GitHub Desktop.
// explore layers in more details, https://effect-ts.github.io/io/modules/Layer.ts.html
import { Context, Effect, Layer } from 'effect'
type A = {
a: (x: number) => Effect.Effect<never, never, number>
}
const A = Context.Tag<A>()
type B = {
b: (x: number) => Effect.Effect<never, never, number>
}
const B = Context.Tag<B>()
type C = {
c: (x: number) => Effect.Effect<never, never, number>
}
const C = Context.Tag<C>()
// ---
const LayerC = Layer.effect(
C,
Effect.gen(function* (_) {
const a = yield* _(A)
const b = yield* _(B)
return {
c: x =>
Effect.gen(function* (_) {
const y = yield* _(a.a(x))
return yield* _(b.b(y))
}),
}
}),
)
//
//
//
//
// standard approach, each layer returns a context with a single service
const LayerA = Layer.succeed(A, { a: x => Effect.succeed(x + 1) })
const LayerB = Layer.succeed(B, { b: x => Effect.succeed(x * 2) })
const LiveLayer = LayerC.pipe(Layer.use(Layer.merge(LayerA, LayerB)))
// alternative approach, layer returns a context with multiple services
// Layer.Layer<never, never, A | B>
const LayerAB = Layer.effectContext(
Effect.gen(function* (_) {
return Context.empty().pipe(
Context.add(A, { a: x => Effect.succeed(x + 1) }),
Context.add(B, { b: x => Effect.succeed(x * 2) }),
)
}),
)
const LiveLayer2 = LayerC.pipe(Layer.use(LayerAB))
// yet another approach, if the dependency between A and B is a simple function
// Layer.Layer<A, never, B>
const LayerBnew = Layer.function(A, B, a => ({ b: x => a.a(x) }))
// Layer.Layer<A, never, A | B>, Layer.service is a way to pass a service from one layer to another
const LayerABnew = Layer.merge(Layer.service(A), LayerBnew)
// Layer.Layer<never, never, C>
const LiveLayer3 = LayerC.pipe(Layer.use(LayerABnew), Layer.use(LayerA))
//
//
//
//
// helper fn so the call site is cleaner
const runProgram = <R, E, E2, A>(
effect: Effect.Effect<R, E, A>,
layer: Layer.Layer<never, E2, R>,
) => Effect.runPromise(Effect.provideLayer(effect, layer))
//
//
//
//
export async function getServerSideProps() {
const program = Effect.gen(function* (_) {
const c = yield* _(C)
return yield* _(c.c(1))
})
return {
props: {
res: {
one: await runProgram(program, LiveLayer),
two: await runProgram(program, LiveLayer2),
three: await runProgram(program, LiveLayer3),
},
},
}
}
const Intro = ({ res }: any) => {
return (
<div>
<pre>{JSON.stringify(res, null, 2)}</pre>
</div>
)
}
export default Intro
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment