Home Reference Source

src/reduce.js

import cons from './cons';
import seq  from './seq';

/**
 * reduced向けのシンボルです。使用しないでください。
 */
export const reducedSymbol = Symbol('reduced');

/**
 * 畳み込みます。f(f(f(init, coll[0]), coll[1]), coll[2])...の結果を返します。
 *
 * @param {*[]} args - [f, init, coll]か[f, coll]のどちらか。
 *
 * @return {*} 畳み込まれた値
 *
 * @example
 * reduce((acc, x) => acc + x, xs);  // xsの合計
 */
export default function reduce(...args) {
  const [f, coll] = (() => {
    switch (args.length) {
    case 0:
      throw 'Invalid arguments';

    case 1:
      throw 'Invalid arguments';

    case 2:
      return args;

    default:
      return [args[0], cons(args[1], args[2])];
    }
  })();

  const iter = seq(coll);
  if (!iter) {
    return null;
  }

  let acc = iter.next().value;

  for (const x of iter) {
    acc = f(acc, x);

    if (acc && acc.hasOwnProperty(reducedSymbol)) {
      acc = acc[reducedSymbol];
      break;
    }
  }

  return acc;
}