Source: list/building.js

/**
 * maryamyriameliamurphies.js
 * A library of Haskell-style morphisms ported to ES2015 JavaScript.
 *
 * list/building.js
 *
 * @file Functions for building lists.
 * @license ISC
 */

/** @module list/building */

import {partial} from '../base';

import {
  emptyList,
  list,
  cons,
  head,
  tail,
  isList,
  isEmpty
} from '../list';

import {error} from '../error';

/**
 * Scan a `List` from the right to left and return a `List` of successive reduced values.
 * <br>`Haskell> scanl :: (b -> a -> b) -> b -> [a] -> [b]`
 * @param {Function} f - The function to map over the `List`
 * @param {*} q - An accumulator value
 * @param {List} ls - The `List` to scan
 * @returns {List} The `List` of reduced values
 * @kind function
 * @example
 * const lst = list(1,2,3);
 * const f = (x, y) => x - y;
 * scanl(f, 0, lst);          // => [0:-1:-3:-6:[]]
 */
export const scanl = (f, q, ls) => {
  const scanl_ = (f, q, ls) => {
    if (isList(ls) === false) { return error.listError(ls, scanl); }
    if (isEmpty(ls)) { return cons(q)(emptyList); }
    const x = head(ls);
    const xs = tail(ls);
    return cons(q)(scanl_(f, f(q, x), xs));
  }
  return partial(scanl_, f, q, ls);
}

/**
 * Like `scanl` but scans left to right instead of right to left.
 * <br>`Haskell> scanr :: (a -> b -> b) -> b -> [a] -> [b]`
 * @param {Function} f - The function to map over the `List`
 * @param {*} q0 - An accumulator value
 * @param {List} as - The `List` to scan
 * @returns {List} The `List` of reduced values
 * @kind function
 * @example
 * const lst = list(1,2,3);
 * const f = (x, y) => x - y;
 * scanr(f, 0, lst);          // => [2:-1:3:0:[]]
 */
export const scanr = (f, q0, as) => {
  const scanr_ = (f, q0, as) => {
    if (isList(as) === false) { return error.listError(as, scanr); }
    if (isEmpty(as)) { return list(q0); }
    const x = head(as);
    const xs = tail(as);
    const qs = scanr(f, q0, xs);
    const q = head(qs);
    return cons(f(x, q))(qs);
  }
  return partial(scanr_, f, q0, as);
}