繰り返し
繰り返しは、ソフトウェア開発における Effect の操作において一般的な要件です。特定の繰り返しポリシーに従って、効果を複数回実行することを可能にします。
repeat
Effect.repeat関数は、指定されたスケジュールに従って、または最初の失敗まで、与えられた効果を繰り返す新しい Effect を返します。
成功の例
import { Effect, Schedule, Console } from "effect";
const action = Console.log("success");
const policy = Schedule.addDelay(Schedule.recurs(2), () => "100 millis");
const program = Effect.repeat(action, policy);
Effect.runPromise(program).then((n) => console.log(`repetitions: ${n}`));/*出力:successsuccesssuccessrepetitions: 2*/失敗の例
import { Effect, Schedule } from "effect";
let count = 0;
// 可能な失敗をシミュレートする非同期のEffectを定義しますconst action = Effect.async<string, string>((resume) => { if (count > 1) { console.log("failure"); resume(Effect.fail("うわっ!")); } else { count++; console.log("success"); resume(Effect.succeed("やった!")); }});
const policy = Schedule.addDelay(Schedule.recurs(2), () => "100 millis");
const program = Effect.repeat(action, policy);
Effect.runPromiseExit(program).then(console.log);/*出力:successsuccessfailure{ _id: 'Exit', _tag: 'Failure', cause: { _id: 'Cause', _tag: 'Fail', failure: 'うわっ!' }}*/最初の発生をスキップする
最初の発生をスキップしたい場合は、Effect.scheduleを使用できます:
import { Effect, Schedule, Console } from "effect";
const action = Console.log("success");
const policy = Schedule.addDelay(Schedule.recurs(2), () => "100 millis");
const program = Effect.schedule(action, policy);
Effect.runPromise(program).then((n) => console.log(`repetitions: ${n}`));/*出力:successsuccessrepetitions: 2*/repeatN
repeatN関数は、指定された効果を指定した回数だけ繰り返す新しい Effect を返します。繰り返しは初回の実行に加算されるため、Effect.repeatN(action, 1)は最初にactionを 1 回実行し、その後成功した場合に追加で 1 回繰り返します。
import { Effect, Console } from "effect";
const action = Console.log("success");
const program = Effect.repeatN(action, 2);
Effect.runPromise(program);/*出力:successsuccesssuccess*/repeatOrElse
repeatOrElse関数は、指定されたスケジュールに従って効果を繰り返す新しい Effect を返します。失敗が発生した場合、失敗値とスケジュールの出力が指定されたハンドラに渡されます。スケジュールされた繰り返しは初回の実行に加算されるため、Effect.repeat(action, Schedule.once)は最初にactionを 1 回実行し、その後成功した場合に追加で 1 回繰り返します。
import { Effect, Schedule } from "effect";
let count = 0;
// 可能な失敗をシミュレートする非同期のEffectを定義しますconst action = Effect.async<string, string>((resume) => { if (count > 1) { console.log("failure"); resume(Effect.fail("うわっ!")); } else { count++; console.log("success"); resume(Effect.succeed("やった!")); }});
const policy = Schedule.addDelay( Schedule.recurs(2), // 最大2回繰り返す () => "100 millis" // 繰り返しの間に100ミリ秒の遅延を追加);
const program = Effect.repeatOrElse(action, policy, () => Effect.sync(() => { console.log("orElse"); return count - 1; }));
Effect.runPromise(program).then((n) => console.log(`repetitions: ${n}`));/*出力:successsuccessfailureorElserepetitions: 1*/条件に基づいて繰り返し
条件を使用して Effect の繰り返しを制御することができます。whileまたはuntilオプションを使用し、ランタイムの結果に基づいて動的に制御することが可能です。
import { Effect } from "effect";
let count = 0;
// 各呼び出し時に異なる結果をシミュレートするEffectを定義しますconst action = Effect.sync(() => { console.log(`Action called ${++count} 回`); return count;});
// 特定の条件が満たされるまでアクションを繰り返しますconst program = Effect.repeat(action, { until: (n) => n === 3 });
Effect.runFork(program);/*出力:Action called 1 回Action called 2 回Action called 3 回*/エラーに基づいて条件を設定するには、Effect.retryの使用を検討してください。