SynchronizedRef
SynchronizedRef<A>は、型Aの値への可変参照として機能します。これを使用することで、不変データを保存し、原子的かつ効果的に更新を行うことができます。
SynchronizedRefのほとんどの操作は、Refの操作に似ています。
もしRefにまだ慣れていない場合は、最初に
Ref の概念を読むことをお勧めします。
SynchronizedRefの独特な機能はupdateEffectです。この関数は効果的な操作を受け取り、それを実行して共有状態を変更します。これがSynchronizedRefをRefと区別する重要な機能です。
import { Effect, SynchronizedRef } from "effect";
const program = Effect.gen(function* () { const ref = yield* SynchronizedRef.make("current"); // 効果的な更新操作をシミュレート const updateEffect = Effect.succeed("update"); yield* SynchronizedRef.updateEffect(ref, () => updateEffect); const value = yield* SynchronizedRef.get(ref); return value;});
Effect.runPromise(program).then(console.log);/*出力:update*/実世界のアプリケーションでは、エフェクト(例えば、データベースのクエリなど)を実行し、その後に共有状態を更新する必要があるシナリオが存在します。これがSynchronizedRefの強みで、アクターモデルの方式で共有状態を更新することを可能にします。私たちは共有の可変状態を持っていますが、各異なるコマンドやメッセージに対して、エフェクトを実行し状態を更新したいのです。
すべての更新に対して効果的なプログラムを渡すことができます。全ての更新は並行して行われますが、その結果は異なる時間に状態に影響を与えるように順序付けられ、最終的には一貫した状態となります。
以下の例では、各ユーザーのgetAgeリクエストを送信し、それに応じて状態を更新します:
import { Effect, SynchronizedRef } from "effect";
// APIをシミュレートconst getAge = (userId: number) => Effect.succeed({ userId, age: userId * 10 });
const users = [1, 2, 3, 4];
const meanAge = Effect.gen(function* () { const ref = yield* SynchronizedRef.make(0);
const log = <R, E, A>(label: string, effect: Effect.Effect<A, E, R>) => Effect.gen(function* () { const value = yield* SynchronizedRef.get(ref); yield* Effect.log(`${label} get: ${value}`); return yield* effect; });
const task = (id: number) => log( `task ${id}`, SynchronizedRef.updateEffect(ref, (sumOfAges) => Effect.gen(function* () { const user = yield* getAge(id); return sumOfAges + user.age; }) ) );
yield* task(1).pipe( Effect.zip(task(2), { concurrent: true }), Effect.zip(task(3), { concurrent: true }), Effect.zip(task(4), { concurrent: true }) );
const value = yield* SynchronizedRef.get(ref); return value / users.length;});
Effect.runPromise(meanAge).then(console.log);/*出力:... fiber=#1 message="task 4 get: 0"... fiber=#2 message="task 3 get: 40"... fiber=#3 message="task 1 get: 70"... fiber=#4 message="task 2 get: 80"25*/