파트10. 비동기 동시성 프로그래밍(2) - ChoDragon9/posts GitHub Wiki

지연 평가 + Promise - L.map, map, take

take, L.map 함수에서 Promise 일 때 동작하도록 수정하면 비동기 데이터와 동기 데이터를 같이 사용할 수 있다.

const take = curry((l, iter) => {
  if (l === 0) return [];
  let res = [];
  iter = L.values(iter);
  return function recur() {
    let cur;
    while (!(cur = iter.next()).done) {
      const a = cur.value;
      if (a instanceof Promise) {
        return a
          .then(a => (res.push(a), res).length == l ? res : recur())
          .catch(e => e == nop ? recur() : Promise.reject(e));
      }
      res.push(a);
      if (res.length == l) return res;
    }
    return res;
  } ();
});
L.map = curry(function *(f, coll) {
  for (const a of L.values(coll)) yield go1(a, f);
});

Kleisli Composition - L.filter, filter, nop, take

filter에 비동기도 전달되는 값의 평가가 거짓일 경우 Promise.reject를 사용합니다. Promise.reject에 인자는 Symbol('nop')이라는 값을 전달합니다. 해당 값을 take에서 처리하게 되면 filter 이후 함수들을 평가가 되지 않습니다.

go([1, 2, 3],
  L.map(v => Promise.resolve(v * v)),
  L.filter(v => v % 2),
  take(2),
  console.log);
L.filter = curry(function *(f, coll) {
  for (const a of L.values(coll)) {
    const b = go1(a, f);
    if (b instanceof Promise) yield b.then(b => b ? a : Promise.reject(nop));
    else if (b) yield a;
  }
});

지연된 함수를 병렬적으로 평가하기 - C.reduce, C.take

지연평가되는 함수들은 평가가 되지 않은 상황에 reduce로 들어오게 됩니다. 그리고 reduce를 평가할 때 수직방향으로 실행하게 됩니다.

go(
  [1, 2],
  L.map(a => delay1000(a * a)),
  L.filter(a => delay1000(a % 2)),
  reduce(add),
  console.log
)

전달되는 이터러블값을 실행하게 되면 모든 값을 병렬적으로 처리할 수 있습니다.

C.reduce = curry((f, acc, iter) => iter ?
  reduce(f, acc, [...iter]) : 
  reduce(f, [...acc]);