Source: traversable.js

/**
 * maryamyriameliamurphies.js
 * A library of Haskell-style morphisms ported to ES2015 JavaScript.
 *
 * traversable.js
 *
 * @file Traversable type class.
 * @license ISC
 */

/** @module traversable */

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

import {
  defines,
  dataType
} from './type';

import {Monad} from './monad';

import {error} from './error';

/**
 * A `Traversable` is a functor representing data structures that can be walked over or "traversed"
 * from left to right (useful in trees, for example). They must define a `traverse` method and also
 * be instances of `Functor` and `Foldable`.
 * @param {*} - Any object
 * @returns {boolean} `true` if an object is an instance of `Traversable` and `false` otherwise
 * @kind function
 */
export const Traversable = defines(`fmap`, `foldr`, `traverse`);

/**
 * Map each element of a structure to an action, evaluate these actions from left to right, and
 * collect the results.
 * <br>`Haskell> traverse :: Applicative f => (a -> f b) -> t a -> f (t b)`
 * @param {Function} f - The function to map
 * @param {Object} a - The traversable structure to traverse
 * @returns {Object} A collection of the results of the traversal
 * @kind function
 * @example
 * const mb = just(1);
 * const tup = tuple(1,2);
 * const lst = list(1,2,3);
 * const f = x => list(x + 7);
 * traverse(f, mb);            // => [Just 8:[]]
 * traverse(f, tup);           // => [(1,9):[]]
 * traverse(f)(lst);           // => [[8:9:10:[]]:[]]
 */
export const traverse = (f, a) => {
  const traverse_ = (f, a) => {
    return Traversable(a) ? dataType(a).traverse(f, a) : error.typeError(a, traverse);
  }
  return partial(traverse_, f, a);
}

/**
 * Map each element of a structure to a monadic action, evaluate these actions from left to right,
 * and collect the results. This function is essentially the same as `traverse` but restricted to
 * monads.
 * <br>`Haskell> mapM :: Monad m => (a -> m b) -> t a -> m (t b)`
 * @param {Function} f - The function to map
 * @param {Object} m - The monad to traverse
 * @returns {Object} A collection of the results of the traversal
 * @kind function
 * @example
 * const mb = just(1);
 * const lst = list(1,2,3);
 * const f = x => list(x + 7);
 * mapM(f, mb);                // => [Just [8:[]]:[]]
 * mapM(f, lst);               // => [[8:9:10:[]]:[[]]:[]]
 */
export const mapM = (f, m) => {
  const mapM_ = (f, m) => Monad(m) ? dataType(m).traverse(f, m) : error.typeError(m, mapM);
  return partial(mapM_, f, m);
}

/**
 * Evaluate each monadic action in a structure from left to right, and collect the results.
 * <br>`Haskell> sequence :: Monad m => t (m a) -> m (t a)`
 * @param {Object} m - The monadic collection of actions
 * @returns {Object} A collection of the results
 * @kind function
 * @example
 * const mb = just(1);
 * const mmb = just(mb);
 * const lst = list(1,2,3);
 * const llst = list(lst);
 * sequence(mmb);           // => Just Just 1
 * sequence(llst);          // => [[1:[]]:[2:[]]:[3:[]]:[]]
 */
export const sequence = m => Monad(m) ? traverse(id, m) : error.typeError(m, sequence);