Reducing
========

.. module:: fun

The section contains functions to analyze iteration values and recombine
through use of a given combining operation the results of recursively processing
its constituent parts, building up a return value

.. contents::

.. note:: An attempt to use infinity iterators with the most function from
          the module causes an infinite loop.

Folds
-----

.. function:: foldl(accfun, initval, gen, param, state)
              iterator:reduce(accfun, initval)

   :param accfun: an accumulating function
   :type  param: (function(prevval, ...) -> val)
   :param initval: an initial value that passed to **accfun** on the first
          iteration

   The function reduces the iterator from left to right using the binary
   operator **accfun** and the initial value **initval**.
   Equivalent to::

        local val = initval
        for _k, ... in gen, param, state do
            val = accfun(val, ...)
        end
        return val

   Examples:

   .. code-block:: lua

    > print(foldl(function(acc, x) return acc + x end, 0, range(5)))
    15

    > print(foldl(operator.add, 0, range(5)))
    15

    > print(foldl(function(acc, x, y) return acc + x * y; end, 0,
        zip(range(1, 5), {4, 3, 2, 1})))
    20

.. function:: reduce(accfun, initval, gen, param, state)
              iterator:reduce(accfun, initval)

   An alias to :func:`foldl`.

.. function:: length(gen, param, state)
              iterator:length()

   :returns: a number of elements in ``gen, param, state`` iterator.

   Return a number of elements in ``gen, param, state`` iterator.
   This function is equivalent to ``#obj`` for basic array and string iterators.

   Examples:

   .. code-block:: lua

    > print(length({"a", "b", "c", "d", "e"}))
    5

    > print(length({}))
    0

    > print(length(range(0)))
    0

   .. warning:: An attempt to call this function on an infinite iterator will
                result an infinite loop.

   .. note:: This function has ``O(n)`` complexity for all iterators except
             basic array and string iterators.

.. function:: totable(gen, param, state)

   :returns: a new table (array) from iterated values.

   The function reduces the iterator from left to right using ``table.insert``.

   Examples:

   .. code-block:: lua

    > local tab = totable("abcdef")
    > print(type(tab), #tab)
    table 6
    > each(print, tab)
    a
    b
    c
    d
    e
    f

.. function:: tomap(gen, param, state)

   :returns: a new table (map) from iterated values.

   The function reduces the iterator from left to right using
   ``tab[val1] = val2`` expression.

   Examples:

   .. code-block:: lua

    > local tab = tomap(zip(range(1, 7), 'abcdef'))
    > print(type(tab), #tab)
    table   6
    > each(print, iter(tab))
    a
    b
    c
    d
    e
    f

Predicates
----------

.. function:: is_prefix_of(iterator1, iterator2)
              iterator1:is_prefix_of(iterator2)

   The function takes two iterators and returns ``true`` if the first iterator
   is a prefix of the second. 

   Examples:

   .. code-block:: lua

    > print(is_prefix_of({"a"}, {"a", "b", "c"}))
    true

    > print(is_prefix_of(range(6), range(5)))
    false

.. function:: is_null(gen, param, state)
              iterator:is_null()

   :returns: true when `gen, param, state`` iterator is empty or finished.
   :returns: false otherwise.

   Example::

    > print(is_null({"a", "b", "c", "d", "e"}))
    false

    > print(is_null({}))
    true

    > print(is_null(range(0)))
    true

.. function:: all(predicate, gen, param, state)
              iterator:all(predicate)

   :param predicate: a predicate

   Returns true if all return values of iterator satisfy the **predicate**.

   Examples:

   .. code-block:: lua

    > print(all(function(x) return x end, {true, true, true, true}))
    true

    > print(all(function(x) return x end, {true, true, true, false}))
    false

.. function:: every(predicate, gen, param, state)

   An alias for :func:`all`.

.. function:: any(predicate, gen, param, state)
              iterator:any(predicate)

   :param predicate: a predicate

   Returns ``true`` if at least one return values of iterator satisfy the
   **predicate**. The iteration stops on the first such value. Therefore,
   infinity iterators that have at least one satisfying value might work.

   Examples:

   .. code-block:: lua

    > print(any(function(x) return x end, {false, false, false, false}))
    false

    > print(any(function(x) return x end, {false, false, false, true}))
    true

.. function:: some(predicate, gen, param, state)

   An alias for :func:`any`.

Special folds
-------------

.. function:: sum(gen, param, state)
              iterator:sum()

   Sum up all iteration values. An optimized alias for::

       foldl(operator.add, 0, gen, param, state)

   For an empty iterator ``0`` is returned.

   Examples:

   .. code-block:: lua

    > print(sum(range(5)))
    15

.. function:: product(gen, param, state)
              iterator:product()

   Multiply all iteration values. An optimized alias for::

       foldl(operator.mul, 1, gen, param, state)

   For an empty iterator ``1`` is returned.

   Examples:

   .. code-block:: lua

    > print(product(range(1, 5)))
    120

.. function:: min(gen, param, state)
              iterator:min()

   Return a minimum value from the iterator using :func:`operator.min` or ``<``
   for numbers and other types respectivly. The iterator must be
   non-null, otherwise an error is raised.

   Examples:

   .. code-block:: lua

    > print(min(range(1, 10, 1)))
    1

    > print(min({"f", "d", "c", "d", "e"}))
    c

    > print(min({}))
    error: min: iterator is empty

.. function:: minimum(gen, param, state)

   An alias for :func:`min`.

.. function:: min_by(cmp, gen, param, state)
              iterator:min_by(cmp)

   Return a minimum value from the iterator using the **cmp** as a ``<``
   operator. The iterator must be non-null, otherwise an error is raised.

   Examples:

   .. code-block:: lua

    > function min_cmp(a, b) if -a < -b then return a else return b end end
    > print(min_by(min_cmp, range(1, 10, 1)))
    9

.. function:: minimum_by(cmp, gen, param, state)

   An alias for :func:`min_by`.

.. function:: max(gen, param, state)
              iterator:max()

   Return a maximum value from the iterator using :func:`operator.max` or ``>``
   for numbers and other types respectivly.

   The iterator must be non-null, otherwise an error is raised.

   Examples:

   .. code-block:: lua

    > print(max(range(1, 10, 1)))
    9

    > print(max({"f", "d", "c", "d", "e"}))
    f

    > print(max({}))
    error: max: iterator is empty

.. function:: maximum(gen, param, state)

   An alias for :func:`max`.

.. function:: max_by(cmp, gen, param, state)
              iterator:max_by(cmp)

   Return a maximum value from the iterator using the **cmp** as a `>`
   operator. The iterator must be non-null, otherwise an error is raised.

   Examples:

   .. code-block:: lua

    > function max_cmp(a, b) if -a > -b then return a else return b end end
    > print(max_by(max_cmp, range(1, 10, 1)))
    1

.. function:: maximum_by(cmp, gen, param, state)

   An alias for :func:`max_by`.
