Source: list/searching.js

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

/** @module list/searching */

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

import {
  Nothing,
  just
} from '../maybe';

import {
  fst,
  snd
} from '../tuple';

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

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

/**
 * Look up a key in an association list. For a list of `Tuple` objects, returns the second element
 * of the first tuple for which the key matches the first element.
 * <br>`Haskell> lookup :: Eq a => a -> [(a, b)] -> Maybe b`
 * @param {*} key - The key value to lookup
 * @param {List} assocs - A `List` of `Tuple` objects
 * @returns {Maybe} The matching value in a `Just` or `Nothing`, otherwise
 * @kind function
 * @example
 * const assocs = list(tuple(1,2), tuple(3,4), tuple(3,3), tuple(4,2));
 * lookup(3, assocs);                                      // => Just 4
 * lookup(5, assocs);                                      // => Nothing
 */
export const lookup = (key, assocs) => {
  const lookup_ = (key, assocs) => {
    if (isList(assocs) === false) { return error.listError(assocs, lookup); }
    if (isEmpty(assocs)) { return Nothing; }
    const xy = head(assocs);
    const xys = tail(assocs);
    const x = fst(xy);
    const y = snd(xy);
    if (key === x) { return just(y); }
    return lookup(key, xys);
  }
  return partial(lookup_, key, assocs);
}

/**
 * Return the `List` of elements in a `List` for which a function `f` returns `true`.
 * <br>`Haskell> filter :: (a -> Bool) -> [a] -> [a]`
 * @param {Function} f - The filter function. Must return a `boolean`
 * @param {List} as - The `List` to filter
 * @returns {List} The filtered `List`
 * @kind function
 * @example
 * const lst = listRange(1,50);
 * const f = x => and(odd(x), greaterThan(x, 10));
 * filter(f, lst); // => [11:13:15:17:19:21:23:25:27:29:31:33:35:37:39:41:43:45:47:49:[]]
 */
export const filter = (f, as) => {
  const filter_ = (f, as) => {
    if (isList(as) === false ) { return error.listError(as, filter); }
    if (isEmpty(as)) { return emptyList; }
    const x = head(as);
    const xs = tail(as);
    if (f(x) === true) { return cons(x)(filter(f, xs)); }
    if (f(x) === false) { return filter(f, xs); }
    return error.returnError(f, filter);
  }
  return partial(filter_, f, as);
}