Layerのメモ化
from Layer (Effect)
https://effect.website/docs/requirements-management/layer-memoization/
Layer.fresh
code:ts
import { Effect, Context, Layer } from "effect";
class A extends Context.Tag("A")<A, { readonly value: number }>() {}
const ALive = Layer.effect(
A,
Effect.gen(function* () {
yield* Effect.log("★★★ Layer A: 初期化されました ★★★");
return { value: 100 };
})
);
// A に依存するプログラム
const consumerProgram = Effect.gen(function* () {
const { value } = yield* A;
yield* Effect.log(サービス A の値を使用: ${value});
});
code:ts
// グローバルな提供と自動メモ化の例
const program1 = Effect.gen(function* () {
yield* Effect.log("====== グローバルな提供と自動メモ化の例 ======");
// 1回目の実行
yield* Effect.log("--- 1回目の実行 ---");
yield* consumerProgram;
// 2回目の実行:同じ Layer インスタンスが再利用される
yield* Effect.log("--- 2回目の実行 (同じ Layer を再利用) ---");
yield* consumerProgram;
}).pipe(
// プログラム全体に Layer を提供
// 最外部で一度だけ provide することで、Layer は自動的にメモ化される
Effect.provide(ALive)
);
code:ts
// ローカルな提供の例
const program2 = Effect.gen(function* () {
yield* Effect.log("====== ローカルな提供と非メモ化の例 ======");
// 1回目のローカル提供
// consumerProgram に直接 provide することで、この時点で Layer が初期化される
yield* Effect.log("--- 1回目のローカル提供 ---");
yield* consumerProgram.pipe(Effect.provide(ALive));
// 2回目のローカル提供
// 別のスコープで provide するため、Layer が再度初期化される
// メモ化されていないので、新しいインスタンスが作成される
yield* Effect.log("--- 2回目のローカル提供 ---");
yield* consumerProgram.pipe(Effect.provide(ALive));
});
code:ts
const program3 = Effect.scoped(
// Layer.memoize により Layer をメモ化
// これは Scoped<Effect<Layer<A>, never, never>> を返す
Layer.memoize(ALive).pipe(
// メモ化された Layer を受け取って処理を実行
Effect.andThen((memoizedLayer) =>
Effect.gen(function* () {
yield* Effect.log(
"====== Layer.memoize を使用した手動メモ化の例 ======"
);
// 1回目のローカル提供
// memoizedLayer はすでにメモ化されているので、
// 初回のみ初期化される
yield* Effect.log("--- 1回目のローカル提供 (メモ化済み) ---");
yield* consumerProgram.pipe(Effect.provide(memoizedLayer));
// 2回目のローカル提供
// 同じメモ化された Layer を使用するため、
// 初期化は行われず、キャッシュされたインスタンスが使われる
yield* Effect.log("--- 2回目のローカル提供 (メモ化済み) ---");
yield* consumerProgram.pipe(Effect.provide(memoizedLayer));
})
)
)
);
Layer.memoizeやEffect.scopedを使っている
code:ts
const main = async () => {
console.log("\n===== Test 1: Global Provision with Auto-Memoization ======");
await Effect.runPromise(program1);
console.log("\n===== Test 2: Local Provision without Memoization ======");
await Effect.runPromise(program2);
console.log("\n===== Test 3: Manual Memoization with Layer.memoize ======");
await Effect.runPromise(program3);
};
main();
code:result
===== Test 1: Global Provision with Auto-Memoization ======
timestamp=2025-10-12T12:37:53.523Z level=INFO fiber=#0 message="★★★ Layer A: 初期化されました ★★★"
timestamp=2025-10-12T12:37:53.525Z level=INFO fiber=#0 message="====== グローバルな提供と自動メモ化の例 ======"
timestamp=2025-10-12T12:37:53.525Z level=INFO fiber=#0 message="--- 1回目の実行 ---"
timestamp=2025-10-12T12:37:53.525Z level=INFO fiber=#0 message="サービス A の値を使用: 100"
timestamp=2025-10-12T12:37:53.525Z level=INFO fiber=#0 message="--- 2回目の実行 (同じ Layer を再利用) ---"
timestamp=2025-10-12T12:37:53.525Z level=INFO fiber=#0 message="サービス A の値を使用: 100"
===== Test 2: Local Provision without Memoization ======
timestamp=2025-10-12T12:37:53.526Z level=INFO fiber=#1 message="====== ローカルな提供と非メモ化の例 ======"
timestamp=2025-10-12T12:37:53.526Z level=INFO fiber=#1 message="--- 1回目のローカル提供 ---"
timestamp=2025-10-12T12:37:53.526Z level=INFO fiber=#1 message="★★★ Layer A: 初期化されました ★★★"
timestamp=2025-10-12T12:37:53.526Z level=INFO fiber=#1 message="サービス A の値を使用: 100"
timestamp=2025-10-12T12:37:53.526Z level=INFO fiber=#1 message="--- 2回目のローカル提供 ---"
timestamp=2025-10-12T12:37:53.527Z level=INFO fiber=#1 message="★★★ Layer A: 初期化されました ★★★"
timestamp=2025-10-12T12:37:53.527Z level=INFO fiber=#1 message="サービス A の値を使用: 100"
===== Test 3: Manual Memoization with Layer.memoize ======
timestamp=2025-10-12T12:37:53.527Z level=INFO fiber=#2 message="====== Layer.memoize を使用した手動メモ化の例 ======"
timestamp=2025-10-12T12:37:53.527Z level=INFO fiber=#2 message="--- 1回目のローカル提供 (メモ化済み) ---"
timestamp=2025-10-12T12:37:53.527Z level=INFO fiber=#2 message="★★★ Layer A: 初期化されました ★★★"
timestamp=2025-10-12T12:37:53.527Z level=INFO fiber=#2 message="サービス A の値を使用: 100"
timestamp=2025-10-12T12:37:53.528Z level=INFO fiber=#2 message="--- 2回目のローカル提供 (メモ化済み) ---"
timestamp=2025-10-12T12:37:53.528Z level=INFO fiber=#2 message="サービス A の値を使用: 100"
program2だけ、Aが2回初期化されてしまっているのがわかる