[functional-js] C.reduce, C.take

21986 ワード


この文章は劉仁東の関数式プログラミングの授業内容を整理した.

並列計算遅延の関数列-C.reduce

const delay1000 = a =>
  new Promise(resolve => setTimeout(() => resolve(a), 1000));

go(
  [1, 2, 3, 4, 5, 6],
  L.map(a => delay1000(a * a)),
  L.filter(a => a % 2),
  reduce(add),
  console.log
);
L.mapでは、実行ごとに約1秒かかります.合計6つのパラメータがあるので、6秒かかります.
コードを実行するたびにコードがループするからです.
並列処理すると、時間が短縮されます.
パラレルオペレーションのC.reduceを作成します.
const C = {};

C.reduce = curry((f, acc, iter) =>
  iter ? reduce(f, acc, [...iter]) : reduce(f, [...acc])
);
reduceを使用して対応するコードをそのまま渡しますが、[...iter]で待機している関数をすべて実行し、再びreduceから値を取り出します.
すなわち,goの最初のパラメータで得られた値をすべて実行した後,それぞれ非同期制御を行い,前から加算を行う.
// 순차적
console.time('');
go(
  [1, 2, 3, 4, 5, 6],
  L.map(a => delay1000(a * a)),
  L.filter(a => a % 2),
  reduce(add),
  console.log, // 35
  _ => console.timeEnd('')
);
// 약 6000ms

// 병렬적
console.time('');
go(
  [1, 2, 3, 4, 5, 6],
  L.map(a => delay1000(a * a)),
  L.filter(a => a % 2),
  C.reduce(add),
  console.log, // 35
  _ => console.timeEnd('')
);
// 약 1000ms
const C = {};
C.reduce = curry((f, acc, iter) =>
  iter ? reduce(f, acc, [...iter]) : reduce(f, [...acc])
);

const delay1000 = a =>
  new Promise(resolve => setTimeout(() => resolve(a), 1000));

go(
  [1, 2, 3, 4, 5, 6],
  L.map(a => delay1000(a * a)),
  L.filter(a => delay1000(a % 2)),
  L.map(a => delay1000(a * a)),
  C.reduce(add),
  console.log
);
catchがない部分はありますが、結果は正常です.
javascriptのプロパティのため、呼び出しスタックにpromissが拒否されている場合は出力されます.
catchでない箇所がありますが、後でよくcatchしてクリーンアップするので、対応するエラーを非同期でキャプチャすることを明確に示す必要があります.
function noop() {}
const catchNoop = arr => (
  arr.forEach(a => (a instanceof Promise ? a.catch(noop) : a)), arr
);

C.reduce = curry((f, acc, iter) => {
  const iter2 = catchNoop(iter ? [...iter] : [...acc]);
  return iter ? reduce(f, acc, iter2) : reduce(f, iter2);
});
以上のように、catchエラーは正常に動作します.
C.take = curry((l, iter) => take(l, catchNoop([...iter])));
takeも同様に書くことができます.
go(
  [1, 2, 3, 4, 5, 6],
  L.map(a => delay1000(a * a)),
  L.filter(a => delay1000(a % 2)),
  L.map(a => delay1000(a * a)),
  C.take(2),
  reduce(add),
  console.log
);
C.takeも並行して実行されるため、既存のtakeよりも運転速度が速い.