Full Code of rtsisyk/luafun for AI

master 12837884993a cached
52 files
132.2 KB
39.3k tokens
1 requests
Download .txt
Repository: rtsisyk/luafun
Branch: master
Commit: 12837884993a
Files: 52
Total size: 132.2 KB

Directory structure:
gitextract_diaikeab/

├── .gitignore
├── .travis.yml
├── CONTRIBUTING.md
├── COPYING.md
├── HACKING.md
├── README.md
├── debian/
│   ├── .gitignore
│   ├── changelog
│   ├── compat
│   ├── control
│   ├── copyright
│   ├── lua-fun.docs
│   ├── lua5.1.dh-lua.conf
│   ├── patches/
│   │   └── series
│   ├── rules
│   ├── source/
│   │   └── format
│   └── watch
├── doc/
│   ├── .gitignore
│   ├── Makefile
│   ├── _static/
│   │   └── .keep
│   ├── _templates/
│   │   └── layout.html
│   ├── about.rst
│   ├── basic.rst
│   ├── compositions.rst
│   ├── conf.py
│   ├── filtering.rst
│   ├── generators.rst
│   ├── getting_started.rst
│   ├── index.rst
│   ├── indexing.rst
│   ├── intro.rst
│   ├── operators.rst
│   ├── reducing.rst
│   ├── reference.rst
│   ├── slicing.rst
│   ├── transformations.rst
│   └── under_the_hood.rst
├── fun-scm-1.rockspec
├── fun.lua
├── rpm/
│   └── lua-fun.spec
└── tests/
    ├── .gitignore
    ├── basic.lua
    ├── compositions.lua
    ├── filtering.lua
    ├── generators.lua
    ├── indexing.lua
    ├── operators.lua
    ├── reducing.lua
    ├── runtest
    ├── slicing.lua
    ├── stateful.lua
    └── transformations.lua

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
*~
temp/
fun.lua.c
5.?-fun/


================================================
FILE: .travis.yml
================================================
sudo: false
language: C
services:
  - docker

env:
    global:
      - PRODUCT=lua-fun
    matrix:
      - OS=el DIST=7
      - OS=fedora DIST=24
      - OS=fedora DIST=25
      - OS=ubuntu DIST=xenial
      - OS=ubuntu DIST=yakkety
      - OS=debian DIST=stretch

before_deploy:
 - git clone https://github.com/packpack/packpack.git packpack
 - ./packpack/packpack

deploy:
  provider: packagecloud
  username: ${PACKAGECLOUD_USER}
  repository: ${PACKAGECLOUD_REPO}
  token: ${PACKAGECLOUD_TOKEN}
  dist: ${OS}/${DIST}
  package_glob: build/*.{deb,rpm}
  skip_cleanup: true
  on:
    branch: master
    condition: -n "${OS}" && -n "${DIST}" && -n "${PACKAGECLOUD_TOKEN}"

after_deploy:
 # Prune old packages from PackageCloud, keep only the last two
 - pip install -r ./packpack/tools/requirements.txt
 - python ./packpack/tools/packagecloud prune ${PACKAGECLOUD_USER}/${PACKAGECLOUD_REPO} deb ${OS} ${DIST} --keep 2
 - python ./packpack/tools/packagecloud prune ${PACKAGECLOUD_USER}/${PACKAGECLOUD_REPO} rpm ${OS} ${DIST} --keep 2

cache:
  directories:
  - $HOME/lua-5.3.2

addons:
  apt:
    packages:
      - lua5.1
      - lua5.2
      - luajit

# Ubuntu Precise on Travis doesn't have lua5.3 package
install:
  - |
    [ -e ${HOME}/lua-5.3.2/src/lua ] || (\
        wget http://www.lua.org/ftp/lua-5.3.2.tar.gz -c && \
        tar xzf lua-5.3.2.tar.gz -C ${HOME} && \
        make -j -C ${HOME}/lua-5.3.2 linux \
    )

script:
  - cd tests
  - LUAJIT=`echo /usr/bin/luajit* | cut -f 1 -d ' '`
  - ${LUAJIT} -v
  - ${LUAJIT} runtest *.lua
  - lua5.1 -v
  - lua5.1 runtest *.lua
  - lua5.2 -v
  - lua5.2 runtest *.lua
  - LUA53=${HOME}/lua-5.3.2/src/lua
  - ${LUA53} -v
  - ${LUA53} runtest *.lua
  - cd ..

notifications:
  email: true


================================================
FILE: CONTRIBUTING.md
================================================
Contributing
============

We'd love for you to contribute to the project and make **Lua Fun** even better
than it is today!

Filling Issues
---------------

Please file bugs reports and feature requests using [GitHub Issues].

[GitHub Issues]: https://github.com/luafun/luafun/issues

Making Changes
--------------

If you want to contribute code, please fork the project on [GitHub], make
changes in branch and send a pull request.

[GitHub]: https://github.com/luafun/luafun


================================================
FILE: COPYING.md
================================================
Copying
=======

**Lua Fun** source codes, logo and documentation are distributed under the
**[MIT/X11 License]** - same as Lua and LuaJIT.

Copyright (c) 2013-2017 Roman Tsisyk <roman@tsisyk.com>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

[MIT/X11 License]: http://www.opensource.org/licenses/mit-license.php


================================================
FILE: HACKING.md
================================================
# Hacking

## Build documentation

Build and open in a Web browser:

```sh
$ cd doc
$ make html
$ xdg-open _build/html/index.html
```

It works with Sphinx 4.3.0 and likely will work with newer versions.


================================================
FILE: README.md
================================================
Lua Functional
==============

<img src="/doc/logo.png" align="right" width="174px" height="144px" />

**Lua Fun** is a high-performance functional programming library for [Lua]
designed with [LuaJIT's trace compiler][LuaJIT] in mind.

Lua Fun provides a set of more than 50 programming primitives typically
found in languages like Standard ML, Haskell, Erlang, JavaScript, Python and
even Lisp. High-order functions such as ``map``, ``filter``, ``reduce``,
``zip``, etc., make it easy to **write simple and efficient functional code**.

Let's see an example:

```lua
> -- Functional style
> require "fun" ()
> -- calculate sum(x for x^2 in 1..n)
> n = 100
> print(reduce(operator.add, 0, map(function(x) return x^2 end, range(n))))
328350

> -- Object-oriented style
> local fun = require "fun"
> -- calculate sum(x for x^2 in 1..n)
> print(fun.range(n):map(function(x) return x^2 end):reduce(operator.add, 0))
328350
```

**Lua Fun** takes full advantage of the innovative **tracing JIT compiler**
to achieve transcendental performance on nested functional expressions.
Functional compositions and high-order functions can be translated into
**efficient machine code**. Can you believe it? Just try to run the example
above with ``luajit -jdump`` and see what happens:

```asm
-- skip some initialization code --
->LOOP:
0bcaffd0  movaps xmm5, xmm7
0bcaffd3  movaps xmm7, xmm1
0bcaffd6  addsd xmm7, xmm5
0bcaffda  ucomisd xmm7, xmm0
0bcaffde  jnb 0x0bca0024        ->5
0bcaffe4  movaps xmm5, xmm7
0bcaffe7  mulsd xmm5, xmm5
0bcaffeb  addsd xmm6, xmm5
0bcaffef  jmp 0x0bcaffd0        ->LOOP
---- TRACE 1 stop -> loop
```

The functional chain above was translated by LuaJIT to (!) **one machine loop**
containing just 10 CPU assembly instructions without CALL. Unbelievable!

Readable? Efficient? Can your Python/Ruby/V8 do better?

Status
------

**Lua Fun** is in an early alpha stage. The library fully
[documented][Documentation] and covered with unit tests.

[![Build Status](https://travis-ci.org/luafun/luafun.png)][Travis]

LuaJIT 2.1 alpha is recommended. The library designed in mind of fact that
[LuaJIT traces tail-, up- and down-recursion][LuaJIT-Recursion] and has a lot of
[byte code optimizations][LuaJIT-Optimizations]. Lua 5.1-5.3 are also
supported.

This is **master** (development) branch. API may be changed without any special
notice. Please use **stable** branch for your production deployments.
If you still want to use **master**, please don't forget to grep `git log`
for *Incompatible API changes* message. Thanks!

Please check out [documentation][Documentation] for more information.

Misc
----

**Lua Fun** is distributed under the [MIT/X11 License] -
(same as Lua and LuaJIT).

The library was written to use with [Tarantool] - an efficient in-memory
store and an asynchronous Lua application server.

See Also
--------

* [Documentation]
* [RockSpec]
* [RPM/DEB packages](https://packagecloud.io/rtsisyk/master)
* [Hacking]
* lua-l@lists.lua.org
* luajit@freelists.org
* roman@tsisyk.com

 [Lua]: https://www.lua.org/
 [LuaJIT]: https://luajit.org/luajit.html
 [LuaJIT-Recursion]: http://lambda-the-ultimate.org/node/3851#comment-57679
 [LuaJIT-Optimizations]: http://wiki.luajit.org/Optimizations
 [MIT/X11 License]: https://opensource.org/licenses/MIT
 [Tarantool]: https://github.com/tarantool/tarantool
 [Getting Started]: https://luafun.github.io/getting_started.html
 [Documentation]: https://luafun.github.io/
 [Travis]: https://travis-ci.org/luafun/luafun
 [RockSpec]: https://raw.github.com/luafun/luafun/master/fun-scm-1.rockspec
 [Hacking]: HACKING.md

Please **"Star"** the project on GitHub to help it to survive! Thanks!

*****

**Lua Fun**. Simple, Efficient and Functional. In Lua. With JIT.


================================================
FILE: debian/.gitignore
================================================
lua-fun/
tmp/
trash
files
lua_versions
*.install
*.substvars
*.log


================================================
FILE: debian/changelog
================================================
lua-fun (0.1.3-1) unstable; urgency=medium

  * Initial release. (Closes: #811482)

 -- Roman Tsisyk <roman@tarantool.org>  Mon, 18 Jan 2016 10:00:00 +0300


================================================
FILE: debian/compat
================================================
9


================================================
FILE: debian/control
================================================
Source: lua-fun
Section: interpreters
Priority: optional
Maintainer: Roman Tsisyk <roman@tarantool.org>
Build-Depends: debhelper (>= 9), dh-lua (>= 19)
Standards-Version: 3.9.6
Homepage: https://github.com/luafun/luafun
Vcs-Git: git://github.com/luafun/luafun.git
Vcs-Browser: https://github.com/luafun/luafun

Package: lua-fun
Architecture: all
Depends: ${misc:Depends}
Provides: ${lua:Provides}
XB-Lua-Versions: ${lua:Versions}
Description: High-performance functional programming library for Lua
 Lua Fun provides a set of more than 50 programming primitives typically
 found in languages like Standard ML, Haskell, Erlang, JavaScript, Python and
 even Lisp. High-order functions such as map, filter, reduce, zip, etc.,
 make it easy to write simple and efficient functional code.


================================================
FILE: debian/copyright
================================================
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: luafun
Upstream-Contact: Roman Tsisyk <roman@tsisyk.com>
Source: https://github.com/luafun/luafun

Files: *
Copyright: 2013-2017 Roman Tsisyk <roman@tsisyk.com>
Comment: In the Lua community this license is better known as "MIT".
  Unfortunately other variants of this license are also known as "MIT".
  To obtain a machine interpretable copyright file Debian prefers to name this
  version of the MIT license using the non ambiguous term "Expat".
License: Expat
 Permission is hereby granted, free of charge, to any person obtaining
 a copy of this software and associated documentation files (the
 “Software”), to deal in the Software without restriction, including
 without limitation the rights to use, copy, modify, merge, publish,
 distribute, sublicense, and/or sell copies of the Software, and to
 permit persons to whom the Software is furnished to do so, subject to
 the following conditions:
 .
 The above copyright notice and this permission notice shall be
 included in all copies or substantial portions of the Software.
 .
 THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
 BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.


================================================
FILE: debian/lua-fun.docs
================================================
README.md


================================================
FILE: debian/lua5.1.dh-lua.conf
================================================
PKG_NAME=fun
LUA_MODNAME=fun
LUA_SOURCES=fun.lua
LUA_TEST=tests/runtest tests/*.lua


================================================
FILE: debian/patches/series
================================================


================================================
FILE: debian/rules
================================================
#!/usr/bin/make -f

VERSION  := $(shell dpkg-parsechangelog|grep ^Version|awk '{print $$2}')
UVERSION := $(shell echo $(VERSION)|sed 's/-[[:digit:]]\+$$//')

%:
	dh $@ --buildsystem=lua --with lua

tarball: clean
		tar --exclude=.git --exclude=debian --exclude rpm \
			--transform='s,^\.,luafun-$(UVERSION),S' \
			-czf ../luafun-$(UVERSION).orig.tar.gz .


================================================
FILE: debian/source/format
================================================
3.0 (quilt)


================================================
FILE: debian/watch
================================================
# test this watch file using:
# uscan --watchfile debian/watch --upstream-version 0.0.1 --package lua-fun
# https://wiki.debian.org/debian/watch#GitHub
version=3
opts=filenamemangle=s/.+\/v?(\d\S*)\.tar\.gz/luafun-$1\.tar\.gz/ \
  https://github.com/luafun/luafun/tags .*/v?(\d\S*)\.tar\.gz


================================================
FILE: doc/.gitignore
================================================
_build


================================================
FILE: doc/Makefile
================================================
# Minimal makefile for Sphinx documentation
#

# You can set these variables from the command line, and also
# from the environment for the first two.
SPHINXOPTS    ?=
SPHINXBUILD   ?= sphinx-build
SOURCEDIR     = .
BUILDDIR      = _build

# Put it first so that "make" without argument is like "make help".
help:
	@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)

.PHONY: help Makefile

# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option.  $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
	@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)


================================================
FILE: doc/_static/.keep
================================================


================================================
FILE: doc/_templates/layout.html
================================================
{% extends "!layout.html" %}

{% block footer %}
{{ super() }}
    <script type="text/javascript">
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');

ga('create', 'UA-45899190-2', 'auto');
ga('send', 'pageview');
    </script>
{% endblock %}


================================================
FILE: doc/about.rst
================================================
About
=====

Credits
-------

An initial prototype was designed and enginered in one evening by Roman Tsisyk.
After that the library was completely rewritten, tested and documented
(which took a while).

The project exists only thanks to the excellent tracing just-in-time compiler
in `LuaJIT <http://luajit.org>`_.

The library works best with `Tarantool <http://tarantool.org>`_ --
an efficient in-memory database and Lua application server.

Copying
-------

Lua Fun source codes, logo and documentation are distributed under the
`MIT License (MIT) <http://www.opensource.org/licenses/mit-license.php>`_ --
same as LuaJIT.

Copyright (c) 2013-2017 Roman Tsisyk <roman@tsisyk.com>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.


================================================
FILE: doc/basic.rst
================================================
Basic Functions
===============

.. currentmodule:: fun

The section contains functions to create iterators from Lua objects.

.. function:: iter(array)
              iter(map)
              iter(string)
              iter(gen, param, state)

   :returns: ``gen, param, state`` -- :ref:`iterator triplet <iterator_triplet>`

   Make ``gen, param, state`` iterator from the iterable object.
   The function is a generalized version of :func:`pairs` and :func:`ipairs`.

   The function distinguish between arrays and maps using ``#arg == 0``
   check to detect maps. For arrays ``ipairs`` is used. For maps a modified
   version of ``pairs`` is used that also returns keys. Userdata objects
   are handled in the same way as tables.

   If ``LUAJIT_ENABLE_LUA52COMPAT`` [#luajit_lua52compat]_ mode is enabled and
   argument has metamethods ``__pairs`` (for maps) or ``__ipairs`` for (arrays),
   call it with the table or userdata as argument and return the first three
   results from the call [#lua52_ipairs]_.

   All library iterator are suitable to use with Lua's ``for .. in`` loop.

   .. code-block:: lua

    > for _it, a in iter({1, 2, 3}) do print(a) end
    1
    2
    3

    > for _it, k, v in iter({ a = 1, b = 2, c = 3}) do print(k, v) end
    b 2
    a 1
    c 3

    > for _it, a in iter("abcde") do print(a) end
    a
    b
    c
    d
    e

   The first cycle variable *_it* is needed to store an internal state of
   the iterator. The value must be always ignored in loops:

   .. code-block:: lua

    for _it, a, b in iter({ a = 1, b = 2, c = 3}) do print(a, b) end
    -- _it is some internal iterator state - always ignore it
    -- a, b are values return from the iterator

   Simple iterators like ``iter({1, 2, 3})`` have simple states, whereas
   other iterators like :func:`zip` or :func:`chain` have complicated
   internal states which values senseless for the end user.

   Check out :doc:`under_the_hood` section for more details.

   There is also the possibility to supply custom iterators to the
   function:

   .. code-block:: lua

    > local function mypairs_gen(max, state)
        if (state >= max) then
                return nil
        end
        return state + 1, state + 1
    end

    > local function mypairs(max)
        return mypairs_gen, max, 0
    end

    > for _it, a in iter(mypairs(10)) do print(a) end
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10

   Iterators can return multiple values.

   Check out :doc:`under_the_hood` section for more details.

   .. [#luajit_lua52compat] http://luajit.org/extensions.html
   .. [#lua52_ipairs] http://www.lua.org/manual/5.2/manual.html#pdf-ipairs

.. function:: each(fun, gen, param, state)
              iterator:each(fun)

   :returns: none

   Execute the *fun* for each iteration value. The function is equivalent to
   the code below:

   .. code-block:: lua

    for _it, ... in iter(gen, param, state) do
        fun(...)
    end

   Examples:

   .. code-block:: lua

    > each(print, { a = 1, b = 2, c = 3})
    b 2
    a 1
    c 3

    > each(print, {1, 2, 3})
    1
    2
    3

   The function is used for its side effects. Implementation directly applies
   *fun* to all iteration values without returning a new iterator, in contrast
   to functions like :func:`map`.

   .. seealso:: :func:`map`, :func:`reduce`

.. function:: for_each(fun, gen, param, state)
              iterator:for_each(fun)

    An alias for :func:`each`.

.. function:: foreach(fun, gen, param, state)
              iterator:foreach(fun)

    An alias for :func:`each`.


================================================
FILE: doc/compositions.rst
================================================
Compositions
============

.. currentmodule:: fun

.. function:: zip(...)
              iterator1:zip(iterator2, iterator3, ...)

   :param ...: iterators to "zip"
   :type  ...: iterator

   :returns: an iterator

   Return a new iterator where i-th return value contains the i-th element
   from each of the iterators. The returned iterator is truncated in length
   to the length of the shortest iterator. For multi-return iterators only the
   first variable is used.

   Examples:

   .. code-block:: lua

    > dump(zip({"a", "b", "c", "d"}, {"one", "two", "three"}))
    a one
    b two
    c three

    > each(print, zip())

    > each(print, zip(range(5), {'a', 'b', 'c'}, rands()))
    1       a       0.57514179487402
    2       b       0.79693061238668
    3       c       0.45174307459403

    > each(print, zip(partition(function(x) return x > 7 end, range(1, 15, 1))))
    8       1
    9       2
    10      3
    11      4
    12      5
    13      6
    14      7

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

   :returns: a cycled version of ``{gen, param, state}`` iterator

   Make a new iterator that returns elements from ``{gen, param, state}``
   iterator until the end and then "restart" iteration using a saved clone of
   ``{gen, param, state}``. The returned iterator is constant space and no
   return values are buffered. Instead of that the function make a clone of the
   source ``{gen, param, state}`` iterator. Therefore, the source iterator
   must be pure functional to make an identical clone. Infinity iterators
   are supported, but are not recommended.

   .. note:: ``{gen, param, state}`` must be pure functional to work properly
            with the function.

   Examples:

   .. code-block:: lua

    > each(print, take(15, cycle(range(5))))
    1
    2
    3
    4
    5
    1
    2
    3
    4
    5
    1
    2
    3
    4
    5

    > each(print, take(15, cycle(zip(range(5), {"a", "b", "c", "d", "e"}))))
    1       a
    2       b
    3       c
    4       d
    5       e
    1       a
    2       b
    3       c
    4       d
    5       e
    1       a
    2       b
    3       c
    4       d
    5       e

.. function:: chain(...)
              iterator1:chain(iterator2, iterator3, ...)

   :param ...: iterators to chain
   :type  ...: iterator
   :returns: a consecutive iterator from sources (left from right)

   Make an iterator that returns elements from the first iterator until it is
   exhausted, then proceeds to the next iterator, until all of the iterators
   are exhausted. Used for treating consecutive iterators as a single iterator.
   Infinity iterators are supported, but are not recommended.

   Examples:

   .. code-block:: lua

    > each(print, chain(range(2), {"a", "b", "c"}, {"one", "two", "three"}))
    1
    2
    a
    b
    c
    one
    two
    three

    > each(print, take(15, cycle(chain(enumerate({"a", "b", "c"}),
        {"one", "two", "three"}))))
    1       a
    2       b
    3       c
    one
    two
    three
    1       a
    2       b
    3       c
    one
    two
    three
    1       a
    2       b
    3       c


================================================
FILE: doc/conf.py
================================================
# Configuration file for the Sphinx documentation builder.
#
# This file only contains a selection of the most common options. For a full
# list see the documentation:
# https://www.sphinx-doc.org/en/master/usage/configuration.html

# -- Path setup --------------------------------------------------------------

# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
# import os
# import sys
# sys.path.insert(0, os.path.abspath('.'))


# -- Project information -----------------------------------------------------

project = 'Lua Functional'
copyright = '2013-2021, Roman Tsisyk'
author = 'Roman Tsisyk'

# The short X.Y version
version = '0.1'

# The full version, including alpha/beta/rc tags
release = '0.1.3'


# -- General configuration ---------------------------------------------------

# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
]

# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']

# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
language = 'en'

# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This pattern also affects html_static_path and html_extra_path.
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']


# -- Options for HTML output -------------------------------------------------

# The theme to use for HTML and HTML Help pages.  See the documentation for
# a list of builtin themes.
#
html_theme = 'haiku'

# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']

# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
html_logo = 'logo.png'

# If true, the reST sources are included in the HTML build as _sources/name.
# The default is True.
html_copy_source = False


================================================
FILE: doc/filtering.rst
================================================
Filtering
=========

.. currentmodule:: fun

This section contains functions to filter values during iteration.

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

   :param param: an predicate to filter the iterator
   :type  param: (function(...) -> bool)

   Return a new iterator of those elements that satisfy the **predicate**.

   Examples:

   .. code-block:: lua

    > each(print, filter(function(x) return x % 3 == 0 end, range(10)))
    3
    6
    9

    > each(print, take(5, filter(function(i, x) return i % 3 == 0 end,
        enumerate(duplicate('x')))))
    3       x
    6       x
    9       x
    12      x
    15      x

   .. note:: Multireturn iterators are supported but can cause performance 
             regressions.

   .. seealso:: :func:`take_while` and :func:`drop_while`.

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

   An alias for :func:`filter`.

.. function:: grep(regexp_or_predicate, gen, param, state)
              iterator:grep(regexp_or_predicate)

   If **regexp_or_predicate** is string then the parameter is used as a regular
   expression to build filtering predicate. Otherwise the function is just an
   alias for :func:`filter`.

   Equivalent to:

   .. code-block:: lua

    local fun = regexp_or_predicate
    if type(regexp_or_predicate) == "string" then
        fun = function(x) return string.find(x, regexp_or_predicate) ~= nil end
    end
    return filter(fun, gen, param, state)

   Examples:

   .. code-block:: lua

    lines_to_grep = {
        [[Emily]],
        [[Chloe]],
        [[Megan]],
        [[Jessica]],
        [[Emma]],
        [[Sarah]],
        [[Elizabeth]],
        [[Sophie]],
        [[Olivia]],
        [[Lauren]]
    }

    each(print, grep("^Em", lines_to_grep))
    --[[test
    Emily
    Emma
    --test]]

    each(print, grep("^P", lines_to_grep))
    --[[test
    --test]]

    > each(print, grep(function(x) return x % 3 == 0 end, range(10)))
    3
    6
    9

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

   :param x: a value to find
   :returns: {gen1, param1, state1}, {gen2, param2, state2}

   The function returns two iterators where elements do and do not satisfy the
   prediucate. Equivalent to:

   .. code-block:: lua

       return filter(predicate, gen', param', state'),
       filter(function(...) return not predicate(...) end, gen, param, state);

   The function make a clone of the source iterator. Iterators especially
   returned in tables to work with :func:`zip` and other functions.

   Examples:

   .. code-block:: lua

    > each(print, zip(partition(function(i, x) return i % 3 == 0 end, range(10))))
    3       1
    6       2
    9       4

   .. note:: ``gen, param, state`` must be pure functional to work properly
             with the function.

   .. seealso:: :func:`span`


================================================
FILE: doc/generators.rst
================================================
Generators
==========

.. currentmodule:: fun

This section contains a number of useful generators modeled after Standard ML,
Haskell, Python, Ruby, JavaScript and other languages.

Finite Generators
-----------------

.. function:: range([start,] stop[, step])

   :param start: an endpoint of the interval (see below)
   :type  start: number
   :param stop: an endpoint of the interval (see below)
   :type  stop: number
   :param step: a step
   :type  step: number

   :returns: an iterator

   The iterator to create arithmetic progressions. Iteration values are generated
   within closed interval ``[start, stop]`` (i.e. *stop* is included).
   If the *start* argument is omitted, it defaults to ``1`` (*stop* > 0) or
   to ``-1`` (*stop* < 0). If the *step* argument is omitted, it defaults to
   ``1`` (*start* <= *stop*) or to ``-1`` (*start* > *stop*).  If *step* is
   positive, the last element is the largest ``start + i * step`` less than or
   equal to *stop*; if *step* is negative, the last element is the smallest
   ``start + i * step`` greater than or equal to *stop*.
   *step* must not be zero (or else an error is raised).
   ``range(0)`` returns empty iterator.

   Examples:

   .. code-block:: lua

    > for _it, v in range(5) do print(v) end
    1
    2
    3
    4
    5
    > for _it, v in range(-5) do print(v) end
    -1
    -2
    -3
    -4
    -5
    > for _it, v in range(1, 6) do print(v) end
    1
    2
    3
    4
    5
    6
    > for _it, v in range(0, 20, 5) do print(v) end
    0
    5
    10
    15
    20
    > for _it, v in range(0, 10, 3) do print(v) end
    0
    3
    6
    9
    > for _it, v in range(0, 1.5, 0.2) do print(v) end
    0
    0.2
    0.4
    0.6
    0.8
    1
    1.2
    1.4
    > for _it, v in range(0) do print(v) end
    > for _it, v in range(1) do print(v) end
    1
    > for _it, v in range(1, 0) do print(v) end
    1
    0
    > for _it, v in range(0, 10, 0) do print(v) end
    error: step must not be zero

Infinity Generators
-------------------

.. function:: duplicate(...)

   :param ...: objects to duplicate
   :type  ...: non nil
   :returns: an iterator

   The iterator returns values over and over again indefinitely. All values
   that passed to the iterator are returned as-is during the iteration.

   Examples:

   .. code-block:: lua

    > each(print, take(3, duplicate('a', 'b', 'c')))
    a       b       c
    a       b       c
    > each(print, take(3, duplicate('x')))
    x
    x
    x
    > for _it, a, b, c, d, e in take(3, duplicate(1, 2, 'a', 3, 'b')) do
        print(a, b, c, d, e)
    >> end
    1       2       a       3       b
    1       2       a       3       b
    1       2       a       3       b

.. function:: xrepeat(...)

   An alias for :func:`duplicate`.

.. function:: replicate(...)

   An alias for :func:`duplicate`.

.. function:: tabulate(fun)

   :param fun: an unary generating function
   :type fun: function(n: uint) -> ... 
   :returns: an iterator

   The iterator that returns ``fun(0)``, ``fun(1)``, ``fun(2)``, ``...`` values
   indefinitely.

   Examples:

   .. code-block:: lua

    > each(print, take(5, tabulate(function(x)  return 'a', 'b', 2*x end)))
    a       b       0
    a       b       2
    a       b       4
    a       b       6
    a       b       8
    > each(print, take(5, tabulate(function(x) return x^2 end)))
    0
    1
    4
    9
    16

.. function:: zeros()

   :returns: an iterator

   The iterator returns ``0`` indefinitely.

   Examples:

   .. code-block:: lua

    > each(print, take(5, zeros()))
    0
    0
    0
    0
    0

.. function:: ones()

   :returns: an iterator

   The iterator that returns ``1`` indefinitely.

   Example::

    > each(print, take(5, ones()))
    1
    1
    1
    1
    1

Random sampling
---------------

.. function:: rands([n[, m]])

   :param n: an endpoint of the interval (see below)
   :type  n: uint
   :param m: an endpoint of the interval (see below)
   :type  m: uint
   :returns: an iterator

   The iterator returns random values using :func:`math.random`.
   If the **n** and **m** are set then the iterator returns pseudo-random
   integers in the ``[n, m)`` interval (i.e. **m** is not included).
   If the **m** is not set then the iterator generates pseudo-random integers
   in the ``[0, n)`` interval. When called without arguments returns
   pseudo-random real numbers with uniform distribution in the
   interval ``[0, 1)``.

   .. warning:: This iterator is not pure-functional and may not work as
                expected with some library functions.

   Examples:

   .. code-block:: lua

    > each(print, take(10, rands(10, 20)))
    19
    17
    11
    19
    12
    13
    14
    16
    10
    11

    > each(print, take(5, rands(10)))
    7
    6
    5
    9
    0

    > each(print, take(5, rands()))
    0.79420629243124
    0.69885246563716
    0.5901037417281
    0.7532286166836
    0.080971251199854



================================================
FILE: doc/getting_started.rst
================================================
Getting Started
===============

Please jump to `Using the Library`_ section if you are familiar with Lua and
LuaJIT.

.. contents::

Prerequisites
-------------

The library is designed for LuaJIT_. **LuaJIT 2.1 alpha** is high^W **Highly**
recommended for performance reasons. Lua 5.1--5.3 are also supported.

The library is platform-independent and expected to work on all platforms that
supported by Lua(JIT). It can be also used in any Lua(JIT) based applications,
e.g. Tarantool_ or OpenResty_.

You might need diff_ tool to run test system and sphinx_ to regenerate the
documentation from source files.

.. _LuaJIT: http://luajit.org/
.. _Tarantool: http://tarantool.org/
.. _OpenResty: http://openresty.org/
.. _diff: http://en.wikipedia.org/wiki/Diff
.. _sphinx: http://sphinx-doc.org/

Installing LuaJIT
-----------------

You can build LuaJIT from sources or install it from a binary archive.

From Sources
````````````

1. Clone LuaJIT git repository. Please note that **v2.1** branch is needed.
You can always select this branch using ``git checkout v2.1``.

.. code-block:: bash

    $ git clone http://luajit.org/git/luajit-2.0.git -b v2.1 luajit-2.1
    Cloning into 'luajit-2.1'...

2. Compile LuaJIT

.. code-block:: bash

    $ cd luajit-2.1/
    luajit-2.1 $ make -j8

3. Install LuaJIT

.. code-block:: bash

    luajit-2.1 $ make install
    luajit-2.1 $ ln -s /usr/local/bin/luajit-2.1.0-alpha /usr/local/bin/luajit

Install operation might require root permissions. However, you can install
LuaJIT into your home directory.

From a Binary Archive
`````````````````````

If operations above look too complicated for you, you always can download a
binary archive from http://luajit.org/download.html page.
Your favorite package manager may also have LuaJIT packages.

Running LuaJIT
``````````````

Ensure that freshly installed LuaJIT works:

.. code-block:: bash

    $ luajit
    LuaJIT 2.1.0-alpha -- Copyright (C) 2005-2013 Mike Pall. http://luajit.org/
    JIT: ON SSE2 SSE3 SSE4.1 fold cse dce fwd dse narrow loop abc sink fuse
    > = 2 + 2
    4

It is good idea to use LuaJIT CLI under ``rlwrap`` (on nix platforms):

.. code-block:: bash

    alias luajit="rlwrap luajit"
    $ luajit
    LuaJIT 2.1.0-alpha -- Copyright (C) 2005-2013 Mike Pall. http://luajit.org/
    JIT: ON SSE2 SSE3 SSE4.1 fold cse dce fwd dse narrow loop abc sink fuse
    > = 2 + 2
    4
    > = 2 + 2 <!-- You can use arrows, completion and so on, like in Bash

Installing the Library
----------------------

Using LuaRocks
``````````````

Use the rockspec_ file.

.. _rockspec: https://raw.github.com/luafun/luafun/master/fun-scm-1.rockspec

Using git
`````````
1. Clone Lua Fun repository:

.. code-block:: bash

    git clone git://github.com/luafun/luafun.git
    $ cd luafun

2. Run tests (optional):

.. code-block:: bash

    luafun $ cd tests
    luafun/tests $ ./runtest *.lua
    Testing basic.lua
    Testing compositions.lua
    Testing filters.lua
    Testing folds.lua
    Testing generators.lua
    Testing slices.lua
    Testing transformations.lua
    All tests have passed!

Using wget
``````````

Just download https://raw.github.com/luafun/luafun/master/fun.lua file:

.. code-block:: bash

    $ wget https://raw.github.com/luafun/luafun/master/fun.lua

Using the Library
-----------------

Try to run LuaJIT in the same directory where ``fun.lua`` file is located:

.. code-block:: bash
   :emphasize-lines: 4

    luafun $ luajit
    LuaJIT 2.1.0-alpha -- Copyright (C) 2005-2013 Mike Pall. http://luajit.org/
    JIT: ON SSE2 SSE3 fold cse dce fwd dse narrow loop abc sink fuse
    > fun = require 'fun'
    >
    > for _k, a in fun.range(3) do print(a) end
    1
    2
    3

If you see an error message like ``stdin:1: module 'fun' not found:`` then
you need to configure you Package Path (``package.path``). Please consult
`Lua Wiki <http://lua-users.org/wiki/PackagePath>`_ for additional information.


**Lua Fun** designed to be small ubiquitous library. It is a good idea to import
all library functions to the global table:

.. code-block:: bash
   :emphasize-lines: 1

    > for k, v in pairs(require "fun") do _G[k] = v end -- import fun.*
    > for _k, a in range(3) do print(a) end
    0
    1
    2

**Lua Fun** also provides a special **shortcut** to autoimport all functions:

.. code-block:: bash
   :emphasize-lines: 1

    > require 'fun'() -- to import all lua.* functions to globals
    > each(print, range(5))
    1
    2
    3
    4
    5

Now you can use **Lua Fun**:

.. code-block:: bash

    > print(sum(filter(function(x) return x % 16 == 0 end, range(10000))))
    3130000

    > each(print, take(5, tabulate(math.sin)))
    0
    2
    4
    6
    8

    > each(print, enumerate(zip({"one", "two", "three", "four", "five"},
        {"a", "b", "c", "d", "e"})))
    1       one     a
    2       two     b
    3       three   c
    4       four    d
    5       five    e

    > lines_to_grep = {
        [[Emily]],
        [[Chloe]],
        [[Megan]],
        [[Jessica]],
        [[Emma]],
        [[Sarah]],
        [[Elizabeth]],
        [[Sophie]],
        [[Olivia]],
        [[Lauren]]
    }

    > each(print, grep("Em", lines_to_grep))
    Emily
    Emma

    > each(print, take(10, cycle(chain(
        {enumerate({"a", "b", "c"})},
        {"one", "two", "three"}))
      ))
    0 a
    1 b
    2 c
    one
    two
    three
    0 a
    1 b
    2 c
    one

Please note that functions support multireturn.

Further Actions
---------------

- Take a look on :doc:`reference`.
- Use :ref:`genindex` to find functions by its names.
- Checkout **examples** from
  `tests/ <https://github.com/luafun/luafun/tree/master/tests>`_ directory
- Read :doc:`under_the_hood` section
- "Star" us the on GitHub_ to help the project to survive
- Make Great Software
- Have fun

**Lua Fun**. Simple, Efficient and Functional. In Lua. With JIT.

.. _GitHub: http://github.com/luafun/luafun


================================================
FILE: doc/index.rst
================================================
.. _library-index:

###############################
  Lua Functional Library
###############################

:Release: |version|
:Date: |today|

.. highlight:: lua

Contents
========

.. toctree::
   :maxdepth: 2

   intro.rst
   getting_started.rst
   reference.rst
   under_the_hood.rst
   about.rst

Indices and tables
==================

* :ref:`genindex`
* :ref:`search`



================================================
FILE: doc/indexing.rst
================================================
Indexing
========

.. currentmodule:: fun

This section contains functions to find elements by its values.

.. function:: index(x, gen, param, state)
              iterator:index(x)

   :param x: a value to find
   :returns: the position of the first element that equals to the **x**

   The function returns the position of the first element in the given iterator
   which is equal (using ``==``) to the query element, or ``nil`` if there is
   no such element.

   Examples:

   .. code-block:: lua

    > print(index(2, range(0)))
    nil

    > print(index("b", {"a", "b", "c", "d", "e"}))
    2

.. function:: index_of(x, gen, param, state)
              iterator:index_of(x)

   An alias for :func:`index`.

.. function:: elem_index(x, gen, param, state)
              iterator:elem_index(x)

   An alias for :func:`index`.

.. function:: indexes(x, gen, param, state)
              iterator:indexes(x)

   :param x: a value to find
   :returns: an iterator which positions of elements that equal to the **x**

   The function returns an iterator to positions of elements which equals to 
   the query element.

   Examples:

   .. code-block:: lua

    > each(print, indexes("a", {"a", "b", "c", "d", "e", "a", "b", "a", "a"}))
    1
    6
    9
    10

   .. seealso:: :func:`filter`

.. function:: indices(x, gen, param, state)
              iterator:indices(x)

   An alias for :func:`indexes`.

.. function:: elem_indexes(x, gen, param, state)
              iterator:elem_indexes(x)

   An alias for :func:`indexes`.

.. function:: elem_indices(x, gen, param, state)
              iterator:elem_indices(x)

   An alias for :func:`indexes`.




================================================
FILE: doc/intro.rst
================================================
Introduction
============

.. currentmodule:: fun

**Lua Fun** is a high-performance functional programming library
designed for `LuaJIT tracing just-in-time compiler
<http://luajit.org/luajit.html>`_.

The library provides a set of more than 50 programming primitives typically
found in languages like Standard ML, Haskell, Erlang, JavaScript, Python and
even Lisp. High-order functions such as :func:`map`, :func:`filter`,
:func:`reduce`, :func:`zip` will help you to **write simple and efficient
functional code**.

Let's see an example:

.. code-block:: lua
   :emphasize-lines: 2, 4

    -- Functional style
    require "fun" ()
    n = 100
    x = sum(map(function(x) return x^2 end, take(n, tabulate(math.sin))))
    -- calculate sum(sin(x)^2 for x in 0..n-1)
    print(x)
    50.011981355266

.. code-block:: lua
   :emphasize-lines: 2, 4

    -- Object-oriented style
    local fun = require "fun"
    n = 100
    x = fun.tabulate(math.sin):take(n):map(function(x) return x^2 end):sum()
    -- calculate sum(sin(x)^2 for x in 0..n-1)
    print(x)
    50.011981355266

**Lua Fun** takes full advantage of the innovative **tracing JIT compiler**
to achieve transcendental performance on nested functional expressions.
Functional compositions and high-order functions can be translated into
**efficient machine code**. Can you believe it? Just try to run the example above
with ``luajit -jdump`` and see what happens:

.. code-block:: none
   :emphasize-lines: 2,14

    -- skip some initialization code --
    ->LOOP:
    0bcaffd0  movsd [rsp+0x8], xmm7
    0bcaffd6  addsd xmm4, xmm5
    0bcaffda  ucomisd xmm6, xmm1
    0bcaffde  jnb 0x0bca0028        ->6
    0bcaffe4  addsd xmm6, xmm0
    0bcaffe8  addsd xmm7, xmm0
    0bcaffec  fld qword [rsp+0x8]
    0bcafff0  fsin
    0bcafff2  fstp qword [rsp]
    0bcafff5  movsd xmm5, [rsp]
    0bcafffa  mulsd xmm5, xmm5
    0bcafffe  jmp 0x0bcaffd0        ->LOOP
    ---- TRACE 1 stop -> loop


The functional chain above was translated by LuaJIT to (!) **one machine loop**
containing just 10 CPU assembly instructions without CALL. Unbelievable!

Readable? Efficient? Can your Python/Ruby/V8 do better?


================================================
FILE: doc/operators.rst
================================================
Operators
=========

.. module:: fun.operator

This auxiliary module exports a set of Lua operators as intrinsic functions
to use with the library high-order primitives.

.. contents::

.. note:: **op** can be used as a shortcut to **operator**.

Comparison operators
--------------------

.. seealso:: `Lua Relational Operators
              <http://www.lua.org/manual/5.2/manual.html#3.4.3>`_

.. function:: le(a, b)

   :returns: **a** <= **b**

.. function:: lt(a, b)

   :returns: **a** < **b**

.. function:: eq(a, b)

   :returns: **a** == **b**

.. function:: ne(a, b)

   :returns: **a** ~= **b**

.. function:: ge(a, b)

   :returns: **a** >= **b**

.. function:: gt(a, b)

   :returns: **a** > **b**

Arithmetic operators
--------------------

.. seealso:: `Lua Arithmetic Operators 
              <http://www.lua.org/manual/5.2/manual.html#3.4.1>`_

.. function:: add(a, b)

   :returns: **a** + **b**

.. function:: div(a, b)

    An alias for :func:`truediv`.

.. function:: truediv(a, b)

   :returns: **a** / **b**

   Performs "true" float division.
   Examples:

   .. code-block:: lua

    > print(operator.div(10, 3))
    3.3333333333333
    > print(operator.div(-10, 3))
    -3.3333333333333

.. function:: floordiv(a, b)

   :returns: math.floor(**a** / **b**)

   Performs division where a result is rounded down. Examples:

   .. code-block:: lua

    > print(operator.floordiv(10, 3))
    3
    > print(operator.floordiv(12, 3))
    4
    > print(operator.floordiv(-10, 3))
    -4
    > print(operator.floordiv(-12, 3))
    -4

.. function:: intdiv(a, b)

   Performs C-like integer division.

   Equivalent to:

   .. code-block:: lua

    function(a, b)
        local q = a / b
        if a >= 0 then return math.floor(q) else return math.ceil(q) end
    end

   Examples:

   .. code-block:: lua

    > print(operator.floordiv(10, 3))
    3
    > print(operator.floordiv(12, 3))
    4
    > print(operator.floordiv(-10, 3))
    -3
    > print(operator.floordiv(-12, 3))
    -4

.. function:: mod(a, b)

   :returns: **a** % **b**

   .. note:: Result has same sign as **divisor**. Modulo in Lua is defined as
             ``a % b == a - math.floor(a/b)*b``.

   Examples:

   .. code-block:: lua
    :emphasize-lines: 5-6

    > print(operator.mod(10, 2))
    0
    > print(operator.mod(10, 3))
    2
    print(operator.mod(-10, 3))
    2 -- == -1 in C, Java, JavaScript and but not in Lua, Python, Haskell!

.. function:: neq(a)

   :returns: -**a**

.. function:: unm(a)

   Unary minus. An alias for :func:`neq`.

.. function:: pow(a, b)

   :returns: math.pow(**a**, **b**)

.. function:: sub(a, b)

   :returns: **a** - **b**

String operators
----------------

.. seealso:: `Lua Concatenation Operator
              <http://www.lua.org/manual/5.2/manual.html#3.4.5>`_

.. function:: concat(a, b)

   :returns: **a** .. **b**

.. function:: len(a)

   :returns: # **a**

.. function:: length(a)

   An alias for :func:`len`.

Logical operators
-----------------

.. seealso:: `Lua Logical Operators
              <http://www.lua.org/manual/5.2/manual.html#3.4.4>`_

.. function:: land(a, b)

   :returns: **a** and **b**

.. function:: lor(a, b)

   :returns: **a** or **b**

.. function:: lnot(a)

   :returns: not **a**

.. function:: truth(a)

   :returns: not not **a**

   Return ``true`` if **a** is true, and ``false`` otherwise. Examples:

   .. code-block:: lua

    > print(operator.truth(1))
    true
    > print(operator.truth(0))
    true -- It is Lua, baby!
    > print(operator.truth(nil))
    false
    > print(operator.truth(""))
    true
    > print(operator.truth({}))
    true



================================================
FILE: doc/reducing.rst
================================================
Reducing
========

.. currentmodule:: 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()

   Return a number of remaining elements in ``gen, param, state`` iterator.

   Examples:

   .. code-block:: lua

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

    > print(length(drop_n(3, {"a", "b", "c", "d", "e"})))
    2

    > 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, where it has ``O(1)`` complexity.

.. 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 respectively. 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 respectively.

   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`.


================================================
FILE: doc/reference.rst
================================================
API Reference
=============

.. module:: fun

.. toctree::

   basic.rst
   generators.rst
   slicing.rst
   indexing.rst
   filtering.rst
   reducing.rst
   transformations.rst
   compositions.rst
   operators.rst


================================================
FILE: doc/slicing.rst
================================================
Slicing
=======

.. currentmodule:: fun

This section contains functions to make subsequences from iterators.

Basic
-----

.. function:: nth(n, gen, param, state)
              iterator:nth(n)

   :param uint n: a sequential number (indexed starting from ``1``,
                  like Lua tables)
   :returns: **n**-th element of ``gen, param, state`` iterator

   This function returns the **n**-th element of ``gen, param, state``
   iterator. If the iterator does not have **n** items then ``nil`` is returned.

   Examples:

   .. code-block:: lua

    > print(nth(2, range(5)))
    2

    > print(nth(10, range(5)))
    nil

    > print(nth(2, {"a", "b", "c", "d", "e"}))
    b

    > print(nth(2, drop_n(3, {"a", "b", "c", "d", "e"})))
    e

    > print(nth(2, enumerate({"a", "b", "c", "d", "e"})))
    2 b

   This function is optimized for basic array and string iterators and has
   ``O(1)`` complexity for these cases.

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

   :returns: a first element of ``gen, param, state`` iterator

   Extract the first element of ``gen, param, state`` iterator.
   If the iterator is empty then an error is raised.

   Examples:

   .. code-block:: lua

    > print(head({"a", "b", "c", "d", "e"}))
    a
    > print(head({}))
    error: head: iterator is empty
    > print(head(range(0)))
    error: head: iterator is empty
    > print(head(enumerate({"a", "b"})))
    1 a

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

   An alias for :func:`head`.

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

   :returns: ``gen, param, state`` iterator without a first element

   Return a copy of ``gen, param, state`` iterator without its first element.
   If the iterator is empty then an empty iterator is returned.

   Examples:

   .. code-block:: lua

    > each(print, tail({"a", "b", "c", "d", "e"}))
    b
    c
    d
    e
    > each(print, tail({}))
    > each(print, tail(range(0)))
    > each(print, tail(enumerate({"a", "b", "c"})))
    2 b
    3 c

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

   An alias for :func:`tail`.

Subsequences
------------

.. function:: take_n(n, gen, param, state)
              iterator:take_n(n)

   :param n: a number of elements to take
   :type  n: uint
   :returns: an iterator on the subsequence of first **n** elements

   Examples:

   .. code-block:: lua

    > each(print, take_n(5, range(10)))
    1
    2
    3
    4
    5

    > each(print, take_n(5, enumerate(duplicate('x'))))
    1 x
    2 x
    3 x
    4 x
    5 x

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

   :type predicate: function(...) -> bool
   :returns: an iterator on the longest prefix of ``gen, param, state``
             elements that satisfy **predicate**.

   Examples:

   .. code-block:: lua

    > each(print, take_while(function(x) return x < 5 end, range(10)))
    1
    2
    3
    4

    > each(print, take_while(function(i, a) return i ~=a end,
        enumerate({5, 3, 4, 4, 2})))
    1       5
    2       3
    3       4

   .. seealso:: :func:`filter`

.. function:: take(n_or_predicate, gen, param, state)
              iterator:take(n_or_predicate)

   An alias for :func:`take_n` and :func:`take_while` that autodetects
   required function based on **n_or_predicate** type.

.. function:: drop_n(n, gen, param, state)
              iterator:drop_n(n)

   :param n: the number of elements to drop
   :type  n: uint
   :returns: ``gen, param, state`` iterator after skipping first **n**
             elements

   Examples:

   .. code-block:: lua

    > each(print, drop_n(2, range(5)))
    3
    4
    5

    > each(print, drop_n(2, enumerate({'a', 'b', 'c', 'd', 'e'})))
    3       c
    4       d
    5       e

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

   :type predicate: function(...) -> bool
   :returns: ``gen, param, state`` after skipping the longest prefix
             of  elements that satisfy **predicate**.

   Examples:

   .. code-block:: lua

    > each(print, drop_while(function(x) return x < 5 end, range(10)))
    5
    6
    7
    8
    9
    10

   .. seealso:: :func:`filter`

.. function:: drop(n_or_predicate, gen, param, state)
              iterator:drop(n_or_predicate)

   An alias for :func:`drop_n` and :func:`drop_while` that autodetects
   required function based on **n_or_predicate** type.


.. function:: span(n_or_predicate, gen, param, state)
              iterator:span(n_or_predicate)

   :type n_or_predicate: function(...) -> bool or uint
   :returns: iterator, iterator

   Return an iterator pair where the first operates on the longest prefix
   (possibly empty) of ``gen, param, state`` iterator of elements that
   satisfy **predicate** and second operates the remainder of
   ``gen, param, state`` iterator. 
   Equivalent to:

   .. code-block:: lua

       return take(n_or_predicate, gen, param, state),
              drop(n_or_predicate, gen, param, state);

   Examples:

   .. code-block:: lua

    > each(print, zip(span(function(x) return x < 5 end, range(10))))
    1       5
    2       6
    3       7
    4       8

    > each(print, zip(span(5, range(10))))
    1       6
    2       7
    3       8
    4       9
    5       10

   .. note:: ``gen, param, state`` must be pure functional to work properly
             with the function.

   .. seealso:: :func:`partition`

.. function:: split(n_or_predicate, gen, param, state)

    An alias for :func:`span`.

.. function:: split_at(n, gen, param, state)

    An alias for :func:`span`.


================================================
FILE: doc/transformations.rst
================================================
Transformations
===============

.. currentmodule:: fun

.. function:: map(fun, gen, param, state)
              iterator:map(fun)

   :param fun: a function to apply
   :type  fun: (function(...) -> ...)
   :returns: a new iterator

   Return a new iterator by applying the **fun** to each element of
   ``gen, param, state`` iterator. The mapping is performed on the fly
   and no values are buffered.

   Examples:

   .. code-block:: lua

    > each(print, map(function(x) return 2 * x end, range(4)))
    2
    4
    6
    8

    fun = function(...) return 'map', ... end
    > each(print, map(fun, range(4)))
    map 1
    map 2
    map 3
    map 4

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

   :returns: a new iterator

   Return a new iterator by enumerating all elements of the
   ``gen, param, state`` iterator starting from ``1``. The mapping is performed
   on the fly and no values are buffered.

   Examples:

   .. code-block:: lua

    > each(print, enumerate({"a", "b", "c", "d", "e"}))
    1 a
    2 b
    3 c
    4 d
    5 e

    > each(print, enumerate(zip({"one", "two", "three", "four", "five"},
        {"a", "b", "c", "d", "e"})))
    1 one a
    2 two b
    3 three c
    4 four d
    5 five e

.. function:: intersperse(x, gen, param, state)
              iterator:intersperse(x)

   :type x: any
   :returns: a new iterator

   Return a new iterator where the **x** value is interspersed between the
   elements of the source iterator. The **x** value can also be added as a
   last element of returning iterator if the source iterator contains the odd
   number of elements.

   Examples:

   .. code-block:: lua

    > each(print, intersperse("x", {"a", "b", "c", "d", "e"}))
    a
    x
    b
    x
    c
    x
    d
    x
    e
    x


================================================
FILE: doc/under_the_hood.rst
================================================
Under the Hood
==============

.. currentmodule:: fun

The section sheds some light on the internal library structure and working
principles.

Iterators
---------

Another basic primitive of the library (after functions) is the iterator. Most functions
take an iterator and return a new iterator or several ones. Iterators all the way down!
[#iterators]_.

The simplest iterators are (surprise!) the :func:`pairs` and :func:`ipairs`
Lua functions. Have you ever tried calling, say, the :func:`ipairs` function
without using it inside a ``for`` loop? Try to do that on any Lua
implementation:

.. _iterator_triplet:
.. code-block:: bash

    > =ipairs({'a', 'b', 'c'})
    function: builtin#6     table: 0x40f80e38       0

The function returned three strange values which look useless without a ``for``
loop. We call these values an **iterator triplet**.
Let's see what each value is used for:

``gen`` -- first value
   A generating function that can produce a next value on each iteration.
   Usually returns a new ``state`` and iteration values (multireturn).

``param`` -- second value
   A permanent (constant) parameter of the generating function. It is used to create
   a specific instance of the generating function. For example, the table itself
   in the ``ipairs`` case.

``state`` -- third value
   A some transient state of an iterator that is changed after each iteration.
   For example, the array index in the ``ipairs`` case.

Try calling the ``gen`` function manually:

   .. code-block:: lua

    > gen, param, state = ipairs({'a', 'b', 'c'})
    > =gen(param, state)
    1       a

The ``gen`` function returned a new state ``1`` and the next iteration
value ``a``. The second call to ``gen`` with the new state will return the next
state and the next iteration value. When the iterator gets to the end
the ``nil`` value is returned instead of the next state.

**Please do not panic!** You do not have to use these values directly.
It is just a nice trick to get ``for .. in`` loops working in Lua.

Iterations
----------

What happens when you type the following code into a Lua console::

    for _it, x in ipairs({'a', 'b', 'c'}) do print(x) end

According to Lua reference manual [#lua_for]_ the code above is equivalent to::

    do
        -- Initialize the iterator
        local gen, param, state = ipairs({'a', 'b', 'c'})
        while true do
            -- Next iteration
            local state, var_1, ···, var_n = gen(param, state)
            if state == nil then break end
            -- Assign values to our variables
            _it = state
            x = var_1
            -- Execute the code block
            print(x)
        end
    end

What does it mean for us?

* An iterator can be used together with ``for .. in`` to generate a loop
* An iterator is fully defined by the ``gen``, ``param`` and ``state`` iterator
  triplet
* The ``nil`` state marks the end of an iteration
* An iterator can return an arbitrary number of values (multireturn)
* It is possible to make some wrapping functions to take an iterator and
  return a new modified iterator

**The library provides a set of iterators** that can be used like ``pairs``
and ``ipairs``.

Iterator Types
--------------

Pure functional iterators
`````````````````````````

Iterators can be either purely functional or have some side effects and return
different values for the same initial conditions [#pure_function]_. An **iterator is
purely functional** if it meets the following criteria:

- ``gen`` function always returns the same values for the same ``param`` and
  ``state`` values (idempotence property)
- ``param`` and ``state`` values are not modified during the ``gen`` call and
  a new ``state`` object is returned instead (referential transparency
  property).

Pure functional iterators are very important for us. Pure functional iterator
can be safety cloned or reapplied without creating side effects. Many library
function use these properties.

Finite iterators
````````````````

Iterators can be **finite** (sooner or later end up) or **infinite**
(never end).
Since there is no way to determine automatically if an iterator is finite or
not [#turing]_ the library function can not automatically resolve infinite
loops. It is your obligation not to pass infinite iterators to reducing
functions.

Tracing JIT
-----------

Tracing just-in-time compilation is a technique used by virtual machines to
optimize the execution of a program at runtime. This is done by recording a
linear sequence of frequently executed operations, compiling them to native
machine code and executing them.

First profiling information for loops is collected. After a hot loop has been
identified, a special tracing mode is entered which records all executed
operations of that loop. This sequence of operations is called a **trace**.
The trace is then optimized and compiled to machine code. When this
loop is executed again the compiled trace is called instead of the program
counterpart [#tracing_jit]_.

Why is tracing JIT important for us? The LuaJIT tracing compiler can detect
tail-, up- and down-recursion [#luajit-recursion]_, unroll compositions of
functions and inline high-order functions [#luajit-optimizations]_.
All of these concepts make the foundation for functional programming.

.. [#iterators] http://en.wikipedia.org/wiki/Turtles_all_the_way_down
.. [#lua_for] http://www.lua.org/manual/5.2/manual.html#3.3.5
.. [#pure_function] http://en.wikipedia.org/wiki/Pure_function
.. [#turing] `Proved by Turing <http://en.wikipedia.org/wiki/Halting_problem>`_
.. [#tracing_jit] http://en.wikipedia.org/wiki/Tracing_just-in-time_compilation
.. [#luajit-recursion] http://lambda-the-ultimate.org/node/3851#comment-57679
.. [#luajit-optimizations] http://wiki.luajit.org/Optimizations


================================================
FILE: fun-scm-1.rockspec
================================================
package = "fun"
version = "scm-1"

source = {
    url = "git+https://github.com/luafun/luafun.git",
}

description = {
    summary = "High-performance functional programming library for Lua",
    homepage = "https://luafun.github.io/",
    license = "MIT/X11",
    maintainer = "Roman Tsisyk <roman@tarantool.org>",
    detailed = [[
Lua Fun is a high-performance functional programming library for Lua
designed with LuaJIT's trace compiler in mind.

Lua Fun provides a set of more than 50 programming primitives typically
found in languages like Standard ML, Haskell, Erlang, JavaScript, Python and
even Lisp. High-order functions such as map, filter, reduce, zip, etc.,
make it easy to write simple and efficient functional code.
]]
}

dependencies = {
    "lua"
}

build = {
    type = "builtin",
    modules = {
        fun = "fun.lua",
    },
    copy_directories = { "tests" },
}


================================================
FILE: fun.lua
================================================
---
--- Lua Fun - a high-performance functional programming library for LuaJIT
---
--- Copyright (c) 2013-2017 Roman Tsisyk <roman@tsisyk.com>
---
--- Distributed under the MIT/X11 License. See COPYING.md for more details.
---

local exports = {}
local methods = {}

-- compatibility with Lua 5.1/5.2
local unpack = rawget(table, "unpack") or unpack

--------------------------------------------------------------------------------
-- Tools
--------------------------------------------------------------------------------

local return_if_not_empty = function(state_x, ...)
    if state_x == nil then
        return nil
    end
    return ...
end

local call_if_not_empty = function(fun, state_x, ...)
    if state_x == nil then
        return nil
    end
    return state_x, fun(...)
end

local function deepcopy(orig) -- used by cycle()
    local orig_type = type(orig)
    local copy
    if orig_type == 'table' then
        copy = {}
        for orig_key, orig_value in next, orig, nil do
            copy[deepcopy(orig_key)] = deepcopy(orig_value)
        end
    else
        copy = orig
    end
    return copy
end

local iterator_mt = {
    -- usually called by for-in loop
    __call = function(self, param, state)
        return self.gen(param, state)
    end;
    __tostring = function(self)
        return '<generator>'
    end;
    -- add all exported methods
    __index = methods;
}

local wrap = function(gen, param, state)
    return setmetatable({
        gen = gen,
        param = param,
        state = state
    }, iterator_mt), param, state
end
exports.wrap = wrap

local unwrap = function(self)
    return self.gen, self.param, self.state
end
methods.unwrap = unwrap

--------------------------------------------------------------------------------
-- Basic Functions
--------------------------------------------------------------------------------

local nil_gen = function(_param, _state)
    return nil
end

local string_gen = function(param, state)
    local state = state + 1
    if state > #param then
        return nil
    end
    local r = string.sub(param, state, state)
    return state, r
end

local ipairs_gen = ipairs({}) -- get the generating function from ipairs

local pairs_gen = pairs({ a = 0 }) -- get the generating function from pairs
local map_gen = function(tab, key)
    local value
    local key, value = pairs_gen(tab, key)
    return key, key, value
end

local rawiter = function(obj, param, state)
    assert(obj ~= nil, "invalid iterator")
    if type(obj) == "table" then
        local mt = getmetatable(obj);
        if mt ~= nil then
            if mt == iterator_mt then
                return obj.gen, obj.param, obj.state
            elseif mt.__ipairs ~= nil then
                return mt.__ipairs(obj)
            elseif mt.__pairs ~= nil then
                return mt.__pairs(obj)
            end
        end
        if #obj > 0 then
            -- array
            return ipairs(obj)
        else
            -- hash
            return map_gen, obj, nil
        end
    elseif (type(obj) == "function") then
        return obj, param, state
    elseif (type(obj) == "string") then
        if #obj == 0 then
            return nil_gen, nil, nil
        end
        return string_gen, obj, 0
    end
    error(string.format('object %s of type "%s" is not iterable',
          obj, type(obj)))
end

local iter = function(obj, param, state)
    return wrap(rawiter(obj, param, state))
end
exports.iter = iter

local method0 = function(fun)
    return function(self)
        return fun(self.gen, self.param, self.state)
    end
end

local method1 = function(fun)
    return function(self, arg1)
        return fun(arg1, self.gen, self.param, self.state)
    end
end

local method2 = function(fun)
    return function(self, arg1, arg2)
        return fun(arg1, arg2, self.gen, self.param, self.state)
    end
end

local export0 = function(fun)
    return function(gen, param, state)
        return fun(rawiter(gen, param, state))
    end
end

local export1 = function(fun)
    return function(arg1, gen, param, state)
        return fun(arg1, rawiter(gen, param, state))
    end
end

local export2 = function(fun)
    return function(arg1, arg2, gen, param, state)
        return fun(arg1, arg2, rawiter(gen, param, state))
    end
end

local each = function(fun, gen, param, state)
    repeat
        state = call_if_not_empty(fun, gen(param, state))
    until state == nil
end
methods.each = method1(each)
exports.each = export1(each)
methods.for_each = methods.each
exports.for_each = exports.each
methods.foreach = methods.each
exports.foreach = exports.each

--------------------------------------------------------------------------------
-- Generators
--------------------------------------------------------------------------------

local range_gen = function(param, state)
    local stop, step = param[1], param[2]
    local state = state + step
    if state > stop then
        return nil
    end
    return state, state
end

local range_rev_gen = function(param, state)
    local stop, step = param[1], param[2]
    local state = state + step
    if state < stop then
        return nil
    end
    return state, state
end

local range = function(start, stop, step)
    if step == nil then
        if stop == nil then
            if start == 0 then
                return nil_gen, nil, nil
            end
            stop = start
            start = stop > 0 and 1 or -1
        end
        step = start <= stop and 1 or -1
    end

    assert(type(start) == "number", "start must be a number")
    assert(type(stop) == "number", "stop must be a number")
    assert(type(step) == "number", "step must be a number")
    assert(step ~= 0, "step must not be zero")

    if (step > 0) then
        return wrap(range_gen, {stop, step}, start - step)
    elseif (step < 0) then
        return wrap(range_rev_gen, {stop, step}, start - step)
    end
end
exports.range = range

local duplicate_table_gen = function(param_x, state_x)
    return state_x + 1, unpack(param_x)
end

local duplicate_fun_gen = function(param_x, state_x)
    return state_x + 1, param_x(state_x)
end

local duplicate_gen = function(param_x, state_x)
    return state_x + 1, param_x
end

local duplicate = function(...)
    if select('#', ...) <= 1 then
        return wrap(duplicate_gen, select(1, ...), 0)
    else
        return wrap(duplicate_table_gen, {...}, 0)
    end
end
exports.duplicate = duplicate
exports.replicate = duplicate
exports.xrepeat = duplicate

local tabulate = function(fun)
    assert(type(fun) == "function")
    return wrap(duplicate_fun_gen, fun, 0)
end
exports.tabulate = tabulate

local zeros = function()
    return wrap(duplicate_gen, 0, 0)
end
exports.zeros = zeros

local ones = function()
    return wrap(duplicate_gen, 1, 0)
end
exports.ones = ones

local rands_gen = function(param_x, _state_x)
    return 0, math.random(param_x[1], param_x[2])
end

local rands_nil_gen = function(_param_x, _state_x)
    return 0, math.random()
end

local rands = function(n, m)
    if n == nil and m == nil then
        return wrap(rands_nil_gen, 0, 0)
    end
    assert(type(n) == "number", "invalid first arg to rands")
    if m == nil then
        m = n
        n = 0
    else
        assert(type(m) == "number", "invalid second arg to rands")
    end
    assert(n < m, "empty interval")
    return wrap(rands_gen, {n, m - 1}, 0)
end
exports.rands = rands

--------------------------------------------------------------------------------
-- Slicing
--------------------------------------------------------------------------------

local nth = function(n, gen_x, param_x, state_x)
    assert(n > 0, "invalid first argument to nth")
    -- An optimization for arrays and strings
    if gen_x == ipairs_gen then
        return param_x[state_x + n]
    elseif gen_x == string_gen then
        if state_x + n <= #param_x then
            return string.sub(param_x, state_x + n, state_x + n)
        else
            return nil
        end
    end
    for i=1,n-1,1 do
        state_x = gen_x(param_x, state_x)
        if state_x == nil then
            return nil
        end
    end
    return return_if_not_empty(gen_x(param_x, state_x))
end
methods.nth = method1(nth)
exports.nth = export1(nth)

local head_call = function(state, ...)
    if state == nil then
        error("head: iterator is empty")
    end
    return ...
end

local head = function(gen, param, state)
    return head_call(gen(param, state))
end
methods.head = method0(head)
exports.head = export0(head)
exports.car = exports.head
methods.car = methods.head

local tail = function(gen, param, state)
    state = gen(param, state)
    if state == nil then
        return wrap(nil_gen, nil, nil)
    end
    return wrap(gen, param, state)
end
methods.tail = method0(tail)
exports.tail = export0(tail)
exports.cdr = exports.tail
methods.cdr = methods.tail

local take_n_gen_x = function(i, state_x, ...)
    if state_x == nil then
        return nil
    end
    return {i, state_x}, ...
end

local take_n_gen = function(param, state)
    local n, gen_x, param_x = param[1], param[2], param[3]
    local i, state_x = state[1], state[2]
    if i >= n then
        return nil
    end
    return take_n_gen_x(i + 1, gen_x(param_x, state_x))
end

local take_n = function(n, gen, param, state)
    assert(n >= 0, "invalid first argument to take_n")
    return wrap(take_n_gen, {n, gen, param}, {0, state})
end
methods.take_n = method1(take_n)
exports.take_n = export1(take_n)

local take_while_gen_x = function(fun, state_x, ...)
    if state_x == nil or not fun(...) then
        return nil
    end
    return state_x, ...
end

local take_while_gen = function(param, state_x)
    local fun, gen_x, param_x = param[1], param[2], param[3]
    return take_while_gen_x(fun, gen_x(param_x, state_x))
end

local take_while = function(fun, gen, param, state)
    assert(type(fun) == "function", "invalid first argument to take_while")
    return wrap(take_while_gen, {fun, gen, param}, state)
end
methods.take_while = method1(take_while)
exports.take_while = export1(take_while)

local take = function(n_or_fun, gen, param, state)
    if type(n_or_fun) == "number" then
        return take_n(n_or_fun, gen, param, state)
    else
        return take_while(n_or_fun, gen, param, state)
    end
end
methods.take = method1(take)
exports.take = export1(take)

local drop_n = function(n, gen, param, state)
    assert(n >= 0, "invalid first argument to drop_n")
    local i
    for i=1,n,1 do
        state = gen(param, state)
        if state == nil then
            return wrap(nil_gen, nil, nil)
        end
    end
    return wrap(gen, param, state)
end
methods.drop_n = method1(drop_n)
exports.drop_n = export1(drop_n)

-- Unpack values from param[3] on the first iteration, then return
-- values from the provided iterator.
--
-- A generator function for drop_while().
local drop_while_gen = function(param, state)
    local results = param[3]
    if not results then
        return param[1](param[2], state)
    else
        param[3] = nil
        return state, unpack(results, 1, table.maxn(results))
    end
end

-- Checks if drop_while should continue skipping. If iterator is not exhausted
-- and skipping is over, elements returned by iterator are wrapped into a table
-- and returned as the second return value. Note that a table is created only
-- once, on the last iteration, for the sake of performance.
local drop_while_x = function(fun, state_x, ...)
    if state_x ~= nil and not fun(...) then
        return state_x, {...}
    end
    return state_x
end

local drop_while = function(fun, gen_x, param_x, state_x)
    assert(type(fun) == "function", "invalid first argument to drop_while")
    local pivot = nil
    while state_x ~= nil and pivot == nil do
        state_x, pivot = drop_while_x(fun, gen_x(param_x, state_x))
    end
    if state_x == nil then
        return wrap(nil_gen, nil, nil)
    end
    return wrap(drop_while_gen, {gen_x, param_x, pivot}, state_x)
end
methods.drop_while = method1(drop_while)
exports.drop_while = export1(drop_while)

local drop = function(n_or_fun, gen_x, param_x, state_x)
    if type(n_or_fun) == "number" then
        return drop_n(n_or_fun, gen_x, param_x, state_x)
    else
        return drop_while(n_or_fun, gen_x, param_x, state_x)
    end
end
methods.drop = method1(drop)
exports.drop = export1(drop)

local split = function(n_or_fun, gen_x, param_x, state_x)
    return take(n_or_fun, gen_x, param_x, state_x),
           drop(n_or_fun, gen_x, param_x, state_x)
end
methods.split = method1(split)
exports.split = export1(split)
methods.split_at = methods.split
exports.split_at = exports.split
methods.span = methods.split
exports.span = exports.split

--------------------------------------------------------------------------------
-- Indexing
--------------------------------------------------------------------------------

local index = function(x, gen, param, state)
    local i = 1
    for _k, r in gen, param, state do
        if r == x then
            return i
        end
        i = i + 1
    end
    return nil
end
methods.index = method1(index)
exports.index = export1(index)
methods.index_of = methods.index
exports.index_of = exports.index
methods.elem_index = methods.index
exports.elem_index = exports.index

local indexes_gen = function(param, state)
    local x, gen_x, param_x = param[1], param[2], param[3]
    local i, state_x = state[1], state[2]
    local r
    while true do
        state_x, r = gen_x(param_x, state_x)
        if state_x == nil then
            return nil
        end
        i = i + 1
        if r == x then
            return {i, state_x}, i
        end
    end
end

local indexes = function(x, gen, param, state)
    return wrap(indexes_gen, {x, gen, param}, {0, state})
end
methods.indexes = method1(indexes)
exports.indexes = export1(indexes)
methods.elem_indexes = methods.indexes
exports.elem_indexes = exports.indexes
methods.indices = methods.indexes
exports.indices = exports.indexes
methods.elem_indices = methods.indexes
exports.elem_indices = exports.indexes

--------------------------------------------------------------------------------
-- Filtering
--------------------------------------------------------------------------------

local filter1_gen = function(fun, gen_x, param_x, state_x, a)
    while true do
        if state_x == nil or fun(a) then break; end
        state_x, a = gen_x(param_x, state_x)
    end
    return state_x, a
end

-- call each other
local filterm_gen
local filterm_gen_shrink = function(fun, gen_x, param_x, state_x)
    return filterm_gen(fun, gen_x, param_x, gen_x(param_x, state_x))
end

filterm_gen = function(fun, gen_x, param_x, state_x, ...)
    if state_x == nil then
        return nil
    end
    if fun(...) then
        return state_x, ...
    end
    return filterm_gen_shrink(fun, gen_x, param_x, state_x)
end

local filter_detect = function(fun, gen_x, param_x, state_x, ...)
    if select('#', ...) < 2 then
        return filter1_gen(fun, gen_x, param_x, state_x, ...)
    else
        return filterm_gen(fun, gen_x, param_x, state_x, ...)
    end
end

local filter_gen = function(param, state_x)
    local fun, gen_x, param_x = param[1], param[2], param[3]
    return filter_detect(fun, gen_x, param_x, gen_x(param_x, state_x))
end

local filter = function(fun, gen, param, state)
    return wrap(filter_gen, {fun, gen, param}, state)
end
methods.filter = method1(filter)
exports.filter = export1(filter)
methods.remove_if = methods.filter
exports.remove_if = exports.filter

local grep = function(fun_or_regexp, gen, param, state)
    local fun = fun_or_regexp
    if type(fun_or_regexp) == "string" then
        fun = function(x) return string.find(x, fun_or_regexp) ~= nil end
    end
    return filter(fun, gen, param, state)
end
methods.grep = method1(grep)
exports.grep = export1(grep)

local partition = function(fun, gen, param, state)
    local neg_fun = function(...)
        return not fun(...)
    end
    return filter(fun, gen, param, state),
           filter(neg_fun, gen, param, state)
end
methods.partition = method1(partition)
exports.partition = export1(partition)

--------------------------------------------------------------------------------
-- Reducing
--------------------------------------------------------------------------------

local foldl_call = function(fun, start, state, ...)
    if state == nil then
        return nil, start
    end
    return state, fun(start, ...)
end

local foldl = function(fun, start, gen_x, param_x, state_x)
    while true do
        state_x, start = foldl_call(fun, start, gen_x(param_x, state_x))
        if state_x == nil then
            break;
        end
    end
    return start
end
methods.foldl = method2(foldl)
exports.foldl = export2(foldl)
methods.reduce = methods.foldl
exports.reduce = exports.foldl

local length = function(gen, param, state)
    if gen == ipairs_gen or gen == string_gen then
        return #param - state
    end
    local len = 0
    repeat
        state = gen(param, state)
        len = len + 1
    until state == nil
    return len - 1
end
methods.length = method0(length)
exports.length = export0(length)

local is_null = function(gen, param, state)
    return gen(param, deepcopy(state)) == nil
end
methods.is_null = method0(is_null)
exports.is_null = export0(is_null)

local is_prefix_of = function(iter_x, iter_y)
    local gen_x, param_x, state_x = iter(iter_x)
    local gen_y, param_y, state_y = iter(iter_y)

    local r_x, r_y
    repeat
        state_x, r_x = gen_x(param_x, state_x)
        if state_x == nil then
            return true
        end

        state_y, r_y = gen_y(param_y, state_y)
    until state_y == nil or r_x ~= r_y

    return false
end
methods.is_prefix_of = is_prefix_of
exports.is_prefix_of = is_prefix_of

local all = function(fun, gen_x, param_x, state_x)
    local r
    repeat
        state_x, r = call_if_not_empty(fun, gen_x(param_x, state_x))
    until state_x == nil or not r
    return state_x == nil
end
methods.all = method1(all)
exports.all = export1(all)
methods.every = methods.all
exports.every = exports.all

local any = function(fun, gen_x, param_x, state_x)
    local r
    repeat
        state_x, r = call_if_not_empty(fun, gen_x(param_x, state_x))
    until state_x == nil or r
    return not not r
end
methods.any = method1(any)
exports.any = export1(any)
methods.some = methods.any
exports.some = exports.any

local sum = function(gen, param, state)
    local s = 0
    local r = 0
    repeat
        s = s + r
        state, r = gen(param, state)
    until state == nil
    return s
end
methods.sum = method0(sum)
exports.sum = export0(sum)

local product = function(gen, param, state)
    local p = 1
    local r = 1
    repeat
        p = p * r
        state, r = gen(param, state)
    until state == nil
    return p
end
methods.product = method0(product)
exports.product = export0(product)

local min_cmp = function(m, n)
    if n < m then return n else return m end
end

local max_cmp = function(m, n)
    if n > m then return n else return m end
end

local min = function(gen, param, state)
    local state, m = gen(param, state)
    if state == nil then
        error("min: iterator is empty")
    end

    local cmp
    if type(m) == "number" then
        -- An optimization: use math.min for numbers
        cmp = math.min
    else
        cmp = min_cmp
    end

    for _, r in gen, param, state do
        m = cmp(m, r)
    end
    return m
end
methods.min = method0(min)
exports.min = export0(min)
methods.minimum = methods.min
exports.minimum = exports.min

local min_by = function(cmp, gen_x, param_x, state_x)
    local state_x, m = gen_x(param_x, state_x)
    if state_x == nil then
        error("min: iterator is empty")
    end

    for _, r in gen_x, param_x, state_x do
        m = cmp(m, r)
    end
    return m
end
methods.min_by = method1(min_by)
exports.min_by = export1(min_by)
methods.minimum_by = methods.min_by
exports.minimum_by = exports.min_by

local max = function(gen_x, param_x, state_x)
    local state_x, m = gen_x(param_x, state_x)
    if state_x == nil then
        error("max: iterator is empty")
    end

    local cmp
    if type(m) == "number" then
        -- An optimization: use math.max for numbers
        cmp = math.max
    else
        cmp = max_cmp
    end

    for _, r in gen_x, param_x, state_x do
        m = cmp(m, r)
    end
    return m
end
methods.max = method0(max)
exports.max = export0(max)
methods.maximum = methods.max
exports.maximum = exports.max

local max_by = function(cmp, gen_x, param_x, state_x)
    local state_x, m = gen_x(param_x, state_x)
    if state_x == nil then
        error("max: iterator is empty")
    end

    for _, r in gen_x, param_x, state_x do
        m = cmp(m, r)
    end
    return m
end
methods.max_by = method1(max_by)
exports.max_by = export1(max_by)
methods.maximum_by = methods.max_by
exports.maximum_by = exports.max_by

local totable = function(gen_x, param_x, state_x)
    local tab, key, val = {}
    while true do
        state_x, val = gen_x(param_x, state_x)
        if state_x == nil then
            break
        end
        table.insert(tab, val)
    end
    return tab
end
methods.totable = method0(totable)
exports.totable = export0(totable)

local tomap = function(gen_x, param_x, state_x)
    local tab, key, val = {}
    while true do
        state_x, key, val = gen_x(param_x, state_x)
        if state_x == nil then
            break
        end
        tab[key] = val
    end
    return tab
end
methods.tomap = method0(tomap)
exports.tomap = export0(tomap)

--------------------------------------------------------------------------------
-- Transformations
--------------------------------------------------------------------------------

local map_gen = function(param, state)
    local gen_x, param_x, fun = param[1], param[2], param[3]
    return call_if_not_empty(fun, gen_x(param_x, state))
end

local map = function(fun, gen, param, state)
    return wrap(map_gen, {gen, param, fun}, state)
end
methods.map = method1(map)
exports.map = export1(map)

local enumerate_gen_call = function(state, i, state_x, ...)
    if state_x == nil then
        return nil
    end
    return {i + 1, state_x}, i, ...
end

local enumerate_gen = function(param, state)
    local gen_x, param_x = param[1], param[2]
    local i, state_x = state[1], state[2]
    return enumerate_gen_call(state, i, gen_x(param_x, state_x))
end

local enumerate = function(gen, param, state)
    return wrap(enumerate_gen, {gen, param}, {1, state})
end
methods.enumerate = method0(enumerate)
exports.enumerate = export0(enumerate)

local intersperse_call = function(i, state_x, ...)
    if state_x == nil then
        return nil
    end
    return {i + 1, state_x}, ...
end

local intersperse_gen = function(param, state)
    local x, gen_x, param_x = param[1], param[2], param[3]
    local i, state_x = state[1], state[2]
    if i % 2 == 1 then
        return {i + 1, state_x}, x
    else
        return intersperse_call(i, gen_x(param_x, state_x))
    end
end

-- TODO: interperse must not add x to the tail
local intersperse = function(x, gen, param, state)
    return wrap(intersperse_gen, {x, gen, param}, {0, state})
end
methods.intersperse = method1(intersperse)
exports.intersperse = export1(intersperse)

--------------------------------------------------------------------------------
-- Compositions
--------------------------------------------------------------------------------

local function zip_gen_r(param, state, state_new, ...)
    if #state_new == #param / 2 then
        return state_new, ...
    end

    local i = #state_new + 1
    local gen_x, param_x = param[2 * i - 1], param[2 * i]
    local state_x, r = gen_x(param_x, state[i])
    if state_x == nil then
        return nil
    end
    table.insert(state_new, state_x)
    return zip_gen_r(param, state, state_new, r, ...)
end

local zip_gen = function(param, state)
    return zip_gen_r(param, state, {})
end

-- A special hack for zip/chain to skip last two state, if a wrapped iterator
-- has been passed
local numargs = function(...)
    local n = select('#', ...)
    if n >= 3 then
        -- Fix last argument
        local it = select(n - 2, ...)
        if type(it) == 'table' and getmetatable(it) == iterator_mt and
           it.param == select(n - 1, ...) and it.state == select(n, ...) then
            return n - 2
        end
    end
    return n
end

local zip = function(...)
    local n = numargs(...)
    if n == 0 then
        return wrap(nil_gen, nil, nil)
    end
    local param = { [2 * n] = 0 }
    local state = { [n] = 0 }

    local i, gen_x, param_x, state_x
    for i=1,n,1 do
        local it = select(n - i + 1, ...)
        gen_x, param_x, state_x = rawiter(it)
        param[2 * i - 1] = gen_x
        param[2 * i] = param_x
        state[i] = state_x
    end

    return wrap(zip_gen, param, state)
end
methods.zip = zip
exports.zip = zip

local cycle_gen_call = function(param, state_x, ...)
    if state_x == nil then
        local gen_x, param_x, state_x0 = param[1], param[2], param[3]
        return gen_x(param_x, deepcopy(state_x0))
    end
    return state_x, ...
end

local cycle_gen = function(param, state_x)
    local gen_x, param_x, state_x0 = param[1], param[2], param[3]
    return cycle_gen_call(param, gen_x(param_x, state_x))
end

local cycle = function(gen, param, state)
    return wrap(cycle_gen, {gen, param, state}, deepcopy(state))
end
methods.cycle = method0(cycle)
exports.cycle = export0(cycle)

-- call each other
local chain_gen_r1
local chain_gen_r2 = function(param, state, state_x, ...)
    if state_x == nil then
        local i = state[1]
        i = i + 1
        if param[3 * i - 2] == nil then
            return nil
        end
        local state_x = param[3 * i]
        return chain_gen_r1(param, {i, state_x})
    end
    return {state[1], state_x}, ...
end

chain_gen_r1 = function(param, state)
    local i, state_x = state[1], state[2]
    local gen_x, param_x = param[3 * i - 2], param[3 * i - 1]
    return chain_gen_r2(param, state, gen_x(param_x, state[2]))
end

local chain = function(...)
    local n = numargs(...)
    if n == 0 then
        return wrap(nil_gen, nil, nil)
    end

    local param = { [3 * n] = 0 }
    local i, gen_x, param_x, state_x
    for i=1,n,1 do
        local elem = select(i, ...)
        gen_x, param_x, state_x = iter(elem)
        param[3 * i - 2] = gen_x
        param[3 * i - 1] = param_x
        param[3 * i] = state_x
    end

    return wrap(chain_gen_r1, param, {1, param[3]})
end
methods.chain = chain
exports.chain = chain

--------------------------------------------------------------------------------
-- Operators
--------------------------------------------------------------------------------

local operator = {
    ----------------------------------------------------------------------------
    -- Comparison operators
    ----------------------------------------------------------------------------
    lt  = function(a, b) return a < b end,
    le  = function(a, b) return a <= b end,
    eq  = function(a, b) return a == b end,
    ne  = function(a, b) return a ~= b end,
    ge  = function(a, b) return a >= b end,
    gt  = function(a, b) return a > b end,

    ----------------------------------------------------------------------------
    -- Arithmetic operators
    ----------------------------------------------------------------------------
    add = function(a, b) return a + b end,
    div = function(a, b) return a / b end,
    floordiv = function(a, b) return math.floor(a/b) end,
    intdiv = function(a, b)
        local q = a / b
        if a >= 0 then return math.floor(q) else return math.ceil(q) end
    end,
    mod = function(a, b) return a % b end,
    mul = function(a, b) return a * b end,
    neq = function(a) return -a end,
    unm = function(a) return -a end, -- an alias
    pow = function(a, b) return a ^ b end,
    sub = function(a, b) return a - b end,
    truediv = function(a, b) return a / b end,

    ----------------------------------------------------------------------------
    -- String operators
    ----------------------------------------------------------------------------
    concat = function(a, b) return a..b end,
    len = function(a) return #a end,
    length = function(a) return #a end, -- an alias

    ----------------------------------------------------------------------------
    -- Logical operators
    ----------------------------------------------------------------------------
    land = function(a, b) return a and b end,
    lor = function(a, b) return a or b end,
    lnot = function(a) return not a end,
    truth = function(a) return not not a end,
}
exports.operator = operator
methods.operator = operator
exports.op = operator
methods.op = operator

--------------------------------------------------------------------------------
-- module definitions
--------------------------------------------------------------------------------

-- a special syntax sugar to export all functions to the global table
setmetatable(exports, {
    __call = function(t, override)
        for k, v in pairs(t) do
            if rawget(_G, k) ~= nil then
                local msg = 'function ' .. k .. ' already exists in global scope.'
                if override then
                    rawset(_G, k, v)
                    print('WARNING: ' .. msg .. ' Overwritten.')
                else
                    print('NOTICE: ' .. msg .. ' Skipped.')
                end
            else
                rawset(_G, k, v)
            end
        end
    end,
})

return exports


================================================
FILE: rpm/lua-fun.spec
================================================
%define luaver 5.3
%define luapkgdir %{_datadir}/lua/%{luaver}
# LuaJIT is compatible with Lua 5.1 and uses the same directory for modules
%global ljpkgdir %{_datadir}/lua/5.1

Name: lua-fun
Version: 0.1.3
Release: 1%{?dist}
Summary: Functional programming library for Lua
Group: Development/Libraries
License: MIT
URL: https://github.com/luafun/luafun
Source0: https://github.com/luafun/luafun/archive/%{version}/luafun-%{version}.tar.gz
BuildArch: noarch
BuildRequires: luajit >= 2.0
BuildRequires: lua >= 5.1
Requires: lua >= 5.1

%package -n luajit-fun
Summary: Functional programming library for LuaJIT
Requires: luajit >= 2.0

%description -n lua-fun
Lua Fun is a high-performance functional programming library for Lua
designed with LuaJIT's trace compiler in mind.

Lua Fun provides a set of more than 50 programming primitives typically
found in languages like Standard ML, Haskell, Erlang, JavaScript, Python and
even Lisp. High-order functions such as map, filter, reduce, zip, etc.,
make it easy to write simple and efficient functional code.

This package provides a module for Lua %{luaver}.

%description -n luajit-fun
Lua Fun is a high-performance functional programming library for Lua
designed with LuaJIT's trace compiler in mind.

Lua Fun provides a set of more than 50 programming primitives typically
found in languages like Standard ML, Haskell, Erlang, JavaScript, Python and
even Lisp. High-order functions such as map, filter, reduce, zip, etc.,
make it easy to write simple and efficient functional code.

This package provides a module for LuaJIT.

%prep
%setup -q -n luafun-%{version}

%build
# nothing to do

%install
# Install for Lua
mkdir -p %{buildroot}%{luapkgdir}
cp -av fun.lua %{buildroot}%{luapkgdir}/fun.lua
# Install for LuaJIT
mkdir -p %{buildroot}%{ljpkgdir}
cp -av fun.lua %{buildroot}%{ljpkgdir}/fun.lua

%check
cd tests
luajit ./runtest *.lua
lua ./runtest *.lua

%files -n lua-fun
%{luapkgdir}/fun.lua
%doc README.md CONTRIBUTING.md
%license COPYING.md

%files -n luajit-fun
%{ljpkgdir}/fun.lua
%doc README.md CONTRIBUTING.md
%license COPYING.md

%changelog
* Mon Jan 18 2016 Roman Tsisyk <roman@tarantool.org> - 0.1.3-1
- Initial version.


================================================
FILE: tests/.gitignore
================================================
*.new


================================================
FILE: tests/basic.lua
================================================
--------------------------------------------------------------------------------
-- iter
--------------------------------------------------------------------------------

--
-- Arrays
--

for _it, a in iter({1, 2, 3}) do print(a) end
--[[test
1
2
3
--test]]

for _it, a in iter(iter(iter({1, 2, 3}))) do print(a) end
--[[test
1
2
3
--test]]

for _it, a in wrap(wrap(iter({1, 2, 3}))) do print(a) end
--[[test
1
2
3
--test]]

for _it, a in wrap(wrap(ipairs({1, 2, 3}))) do print(a) end
--[[test
1
2
3
--test]]

for _it, a in iter({}) do print(a) end
--[[test
--test]]

for _it, a in iter(iter(iter({}))) do print(a) end
--[[test
--test]]

for _it, a in wrap(wrap(iter({}))) do print(a) end
--[[test
--test]]

for _it, a in wrap(wrap(ipairs({}))) do print(a) end
--[[test
--test]]

-- Check that ``iter`` for arrays is equivalent to ``ipairs``
local t = {1, 2, 3}
gen1, param1, state1 = iter(t):unwrap()
gen2, param2, state2 = ipairs(t) 
print(gen1 == gen2, param1 == param2, state1 == state2)
--[[test
true true true
--test]]

-- Test that ``wrap`` do nothing for wrapped iterators
gen1, param1, state1 = iter({1, 2, 3})
gen2, param2, state2 = wrap(gen1, param1, state1):unwrap()
print(gen1 == gen2, param1 == param2, state1 == state2)
--[[test
true true true
--test]]

--
-- Maps
--

local t = {}
for _it, k, v in iter({ a = 1, b = 2, c = 3}) do t[#t + 1] = k end
table.sort(t)
for _it, v in iter(t) do print(v) end
--[[test
a
b
c
--test]]

local t = {}
for _it, k, v in iter(iter(iter({ a = 1, b = 2, c = 3}))) do t[#t + 1] = k end
table.sort(t)
for _it, v in iter(t) do print(v) end
--[[test
a
b
c
--test]]

for _it, k, v in iter({}) do print(k, v) end
--[[test
--test]]

for _it, k, v in iter(iter(iter({}))) do print(k, v) end
--[[test
--test]]

--
-- String
--

for _it, a in iter("abcde") do print(a) end
--[[test
a
b
c
d
e
--test]]

for _it, a in iter(iter(iter("abcde"))) do print(a) end
--[[test
a
b
c
d
e
--test]]

for _it, a in iter("") do print(a) end
--[[test
--test]]

for _it, a in iter(iter(iter(""))) do print(a) end
--[[test
--test]]

--
-- Custom generators
--

local function mypairs_gen(max, state)
    if (state >= max) then
            return nil
        end
        return state + 1, state + 1
end

local function mypairs(max)
    return mypairs_gen, max, 0
end

for _it, a in iter(mypairs(10)) do print(a) end
--[[test
1
2
3
4
5
6
7
8
9
10
--test]]

--
-- Invalid values
--

for _it, a in iter(1) do print(a) end
--[[test
error: object 1 of type "number" is not iterable
--test]]

for _it, a in iter(1, 2, 3, 4, 5, 6, 7) do print(a) end
--[[test
error: object 1 of type "number" is not iterable
--test]]

--------------------------------------------------------------------------------
-- each
--------------------------------------------------------------------------------

each(print, {1, 2, 3})
--[[test
1
2
3
--test]]

each(print, iter({1, 2, 3}))
--[[test
1
2
3
--test]]

each(print, {})
--[[test
--test]]


each(print, iter({}))
--[[test
--test]]

local keys, vals = {}, {}
each(function(k, v)
    keys[#keys + 1] = k
    vals[#vals + 1] = v
end, { a = 1, b = 2, c = 3})
table.sort(keys)
table.sort(vals)
each(print, keys)
each(print, vals)
--[[test
a
b
c
1
2
3
--test]]

each(print, "abc")
--[[test
a
b
c
--test]]

each(print, iter("abc"))
--[[test
a
b
c
--test]]

print(for_each == each) -- an alias
--[[test
true
--test]]

print(foreach == each) -- an alias
--[[test
true
--test]]

--------------------------------------------------------------------------------
-- totable
--------------------------------------------------------------------------------

local tab = totable(range(5))
print(type(tab), #tab)
each(print, tab)
--[[test
table 5
1
2
3
4
5
--test]]

local tab = totable(range(0))
print(type(tab), #tab)
--[[test
table 0
--test]]

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

local unpack = rawget(table, "unpack") or unpack
local tab = totable({ 'a', {'b', 'c'}, {'d', 'e', 'f'}})
print(type(tab), #tab)
each(print, tab[1])
each(print, map(unpack, drop(1, tab)))
--[[test
table 3
a
b c
d e f
--test]]

--------------------------------------------------------------------------------
-- tomap
--------------------------------------------------------------------------------

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

local tab = tomap({a = 1, b = 2, c = 3})
print(type(tab), #tab)
local t = {}
for _it, k, v in iter(tab) do t[v] = k end
table.sort(t)
for k, v in ipairs(t) do print(k, v) end
--[[test
table 0
1 a
2 b
3 c
--test]]

local tab = tomap(enumerate("abcdef"))
print(type(tab), #tab)
each(print, tab)
--[[test
table 6
a
b
c
d
e
f
--test]]


================================================
FILE: tests/compositions.lua
================================================
--------------------------------------------------------------------------------
-- zip
--------------------------------------------------------------------------------

dump(zip({"a", "b", "c", "d"}, {"one", "two", "three"}))
--[[test
a one
b two
c three
--test]]

dump(zip())
--[[test
--test]]

dump(zip(range(0)))
--[[test
error: invalid iterator
--test]]

dump(zip(range(0), range(0)))
--[[test
error: invalid iterator
--test]]

print(nth(10, zip(range(1, 100, 3), range(1, 100, 5), range(1, 100, 7))))
--[[test
28 46 64
--test]]

dump(zip(partition(function(x) return x > 7 end, range(1, 15, 1))))
--[[test
8 1
9 2
10 3
11 4
12 5
13 6
14 7
--test]]

--------------------------------------------------------------------------------
-- cycle
--------------------------------------------------------------------------------

dump(take(15, cycle({"a", "b", "c", "d", "e"})))
--[[test
a
b
c
d
e
a
b
c
d
e
a
b
c
d
e
--test]]


dump(take(15, cycle(range(5))))
--[[test
1
2
3
4
5
1
2
3
4
5
1
2
3
4
5
--test]]

dump(take(15, cycle(zip(range(5), {"a", "b", "c", "d", "e"}))))
--[[test
1 a
2 b
3 c
4 d
5 e
1 a
2 b
3 c
4 d
5 e
1 a
2 b
3 c
4 d
5 e
--test]]

--------------------------------------------------------------------------------
-- chain
--------------------------------------------------------------------------------

dump(chain(range(2)))
--[[test
1
2
--test]]

dump(chain(range(2), {"a", "b", "c"}, {"one", "two", "three"}))
--[[test
1
2
a
b
c
one
two
three
--test]]

dump(take(15, cycle(chain(enumerate({"a", "b", "c"}),
    {"one", "two", "three"}))))
--[[test
1 a
2 b
3 c
one
two
three
1 a
2 b
3 c
one
two
three
1 a
2 b
3 c
--test]]

local tab = {}
local keys = {}
for _it, k, v in chain({ a = 11, b = 12, c = 13}, { d = 21, e = 22 }) do
    tab[k] = v
    table.insert(keys, k)
end
table.sort(keys)
for _, key in ipairs(keys) do print(key, tab[key]) end
--[[test
a 11
b 12
c 13
d 21
e 22
--test]]

dump(chain(range(0), range(0), range(0)))
--[[test
error: invalid iterator
--test]]

dump(chain(range(0), range(1), range(0)))
--[[test
error: invalid iterator
--test]]

-- Similar to fun.range(), but accepts just 'stop' for simplicity.
--
-- The key point of this iterator generator is that it doesn't use
-- 'param' (the second value in the gen-param-state triplet) and
-- pass nil to it. This is needed to reproduce the next scenario.
function myrange(stop)
    local function gen(_param, i)
        if i < stop then
            return i + 1, i + 1
        end
        return nil
    end
    return wrap(gen, nil, 0)
end

-- gh-86: verify that chain don't stop on an iterator that uses
-- param = nil.
dump(chain(myrange(3), myrange(3), myrange(3)))
--[[test
1
2
3
1
2
3
1
2
3
--test]]


================================================
FILE: tests/filtering.lua
================================================
--------------------------------------------------------------------------------
-- filter
--------------------------------------------------------------------------------

dump(filter(function(x) return x % 3 == 0 end, range(10)))
--[[test
3
6
9
--test]]

dump(filter(function(x) return x % 3 == 0 end, range(0)))
--[[test
--test]]


dump(take(5, filter(function(i, x) return i % 3 == 0 end,
    enumerate(duplicate('x')))))
--[[test
3 x
6 x
9 x
12 x
15 x
--test]]

function filter_fun(a, b, c)
    if a % 16 == 0 then
        return true
    else
        return false
    end
end

function test3(a, b, c)
    return a, c, b
end

n = 50
dump(filter(filter_fun, map(test3, zip(range(0, n, 1),
     range(0, n, 2), range(0, n, 3)))))
--[[test
0 0 0
16 48 32
--test]]

print(remove_if == filter) -- an alias
--[[test
true
--test]]

dump_state(filter(function(x) return x % 2 == 0 end, ipairs({0, 1, 1, 2, 3, 4})))
--[[test
1
4
6
--test]]

--------------------------------------------------------------------------------
-- grep
--------------------------------------------------------------------------------

lines_to_grep = {
    [[Lorem ipsum dolor sit amet, consectetur adipisicing elit, ]],
    [[sed do eiusmod tempor incididunt ut labore et dolore magna ]],
    [[aliqua. Ut enim ad minim veniam, quis nostrud exercitation ]],
    [[ullamco laboris nisi ut aliquip ex ea commodo consequat.]],
    [[Duis aute irure dolor in reprehenderit in voluptate velit ]],
    [[esse cillum dolore eu fugiat nulla pariatur. Excepteur sint ]],
    [[occaecat cupidatat non proident, sunt in culpa qui officia ]],
    [[deserunt mollit anim id est laborum.]]
}

dump(grep("lab", lines_to_grep))
--[[test
sed do eiusmod tempor incididunt ut labore et dolore magna 
ullamco laboris nisi ut aliquip ex ea commodo consequat.
deserunt mollit anim id est laborum.
--test]]

lines_to_grep = {
    [[Emily]],
    [[Chloe]],
    [[Megan]],
    [[Jessica]],
    [[Emma]],
    [[Sarah]],
    [[Elizabeth]],
    [[Sophie]],
    [[Olivia]],
    [[Lauren]]
}

dump(grep("^Em", lines_to_grep))
--[[test
Emily
Emma
--test]]

dump_state(grep("^Em", lines_to_grep))
--[[test
1
5
--test]]

--------------------------------------------------------------------------------
-- partition
--------------------------------------------------------------------------------

dump(zip(partition(function(i, x) return i % 3 == 0 end, range(10))))
--[[test
3 1
6 2
9 4
--test]]


================================================
FILE: tests/generators.lua
================================================
--------------------------------------------------------------------------------
-- range
--------------------------------------------------------------------------------

dump(range(0))
print('--')
for i=1,0 do print(i) end
--[[test
--
--test]]

dump(range(0, 0))
print('--')
for i=0,0 do print(i) end
--[[test
0
--
0
--test]]

dump(range(5))
print('--')
for i=1,5 do print(i) end
--[[test
1
2
3
4
5
--
1
2
3
4
5
--test]]

dump(range(0, 5))
print('--')
for i=0,5 do print(i) end
--[[test
0
1
2
3
4
5
--
0
1
2
3
4
5
--test]]

dump(range(0, 5, 1))
print('--')
for i=0,5,1 do print(i) end
--[[test
0
1
2
3
4
5
--
0
1
2
3
4
5
--test]]

dump(range(0, 10, 2))
print('--')
for i=0,10,2 do print(i) end
--[[test
0
2
4
6
8
10
--
0
2
4
6
8
10
--test]]

dump(range(-5))
print('--')
for i=-1,-5,-1 do print(i) end
--[[test
-1
-2
-3
-4
-5
--
-1
-2
-3
-4
-5
--test]]

dump(range(0, -5, 1))
print('--')
for i=0,-5,1 do print(i) end
--[[test
--
--test]]

dump(range(0, -5, -1))
print('--')
for i=0,-5,-1 do print(i) end
--[[test
0
-1
-2
-3
-4
-5
--
0
-1
-2
-3
-4
-5
--test]]

dump(range(0, -10, -2))
print('--')
for i=0,-10,-2 do print(i) end
--[[test
0
-2
-4
-6
-8
-10
--
0
-2
-4
-6
-8
-10
--test]]

dump(range(1.2, 1.6, 0.1))
--[[test
1.2
1.3
1.4
1.5
--test]]

-- Invalid step
dump(range(0, 5, 0))
--[[test
error: step must not be zero
--test]]

--------------------------------------------------------------------------------
-- duplicate
--------------------------------------------------------------------------------

dump(take(5, duplicate(48)))
--[[test
48
48
48
48
48
--test]]

dump(take(5, duplicate(1,2,3,4,5)))
--[[test
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
--test]]

print(xrepeat == duplicate) -- an alias
--[[test
true
--test]]

print(replicate == duplicate) -- an alias
--[[test
true
--test]]

--------------------------------------------------------------------------------
-- tabulate
--------------------------------------------------------------------------------

dump(take(5, tabulate(function(x) return 2 * x end)))
--[[test
0
2
4
6
8
--test]]

--------------------------------------------------------------------------------
-- zeros
--------------------------------------------------------------------------------

dump(take(5, zeros()))
--[[test
0
0
0
0
0
--test]]

--------------------------------------------------------------------------------
-- ones
--------------------------------------------------------------------------------

dump(take(5, ones()))
--[[test
1
1
1
1
1
--test]]

--------------------------------------------------------------------------------
-- rands
--------------------------------------------------------------------------------

print(all(function(x) return x >= 0 and x < 1 end, take(5, rands())))
--[[test
true
--test]]

dump(take(5, rands(0)))
--[[test
error: empty interval
--test]]

print(all(function(x) return math.floor(x) == x end, take(5, rands(10))))
--[[test
true
--test]]

print(all(function(x) return math.floor(x) == x end, take(5, rands(1024))))
--[[test
true
--test]]

dump(take(5, rands(0, 1)))
--[[test
0
0
0
0
0
--test]]

dump(take(5, rands(5, 6)))
--[[test
5
5
5
5
5
--test]]

print(all(function(x) return x >= 10 and x < 20 end, take(20, rands(10, 20))))
--[[test
true
--test]]


================================================
FILE: tests/indexing.lua
================================================
--------------------------------------------------------------------------------
-- index
--------------------------------------------------------------------------------

print(index(2, range(5)))
--[[test
2
--test]]

print(index(10, range(5)))
--[[test
nil
--test]]

print(index(2, range(0)))
--[[test
nil
--test]]

print(index("b", {"a", "b", "c", "d", "e"}))
--[[test
2
--test]]

print(index(1, enumerate({"a", "b", "c", "d", "e"})))
--[[test
1
--test]]

print(index("b", "abcdef"))
--[[test
2
--test]]

print(index_of == index) -- an alias
--[[test
true
--test]]

print(elem_index == index) -- an alias
--[[test
true
--test]]

--------------------------------------------------------------------------------
-- indexes
--------------------------------------------------------------------------------

dump(indexes("a", {"a", "b", "c", "d", "e", "a", "b", "c", "d", "a", "a"}))
--[[test
1
6
10
11
--test]]

dump(indexes("f", {"a", "b", "c", "d", "e", "a", "b", "c", "d", "a", "a"}))
--[[test
--test]]

dump(indexes("f", {}))
--[[test
--test]]

dump(indexes(1, enumerate({"a", "b", "c", "d", "e"})))
--[[test
1
--test]]

print(indices == indexes) -- an alias
--[[test
true
--test]]

print(elem_indexes == indexes) -- an alias
--[[test
true
--test]]

print(elem_indices == indexes) -- an alias
--[[test
true
--test]]


================================================
FILE: tests/operators.lua
================================================
--
-- All these functions are fully covered by Lua tests.
-- This test just checks that all functions were defined correctly.
--

print(op == operator) -- an alias
--[[test
true
--test]]

--------------------------------------------------------------------------------
-- Comparison operators
--------------------------------------------------------------------------------

local comparators = { 'le', 'lt', 'eq', 'ne', 'ge', 'gt' }
for _k, op in iter(comparators) do
    print('op', op)
    print('==')
    print('num:')
    print(operator[op](0, 1))
    print(operator[op](1, 0))
    print(operator[op](0, 0))
    print('str:')
    print(operator[op]("abc", "cde"))
    print(operator[op]("cde", "abc"))
    print(operator[op]("abc", "abc"))
    print('')
end
--[[test
op le
==
num:
true
false
true
str:
true
false
true

op lt
==
num:
true
false
false
str:
true
false
false

op eq
==
num:
false
false
true
str:
false
false
true

op ne
==
num:
true
true
false
str:
true
true
false

op ge
==
num:
false
true
true
str:
false
true
true

op gt
==
num:
false
true
false
str:
false
true
false

--test]]

--------------------------------------------------------------------------------
-- Arithmetic operators
--------------------------------------------------------------------------------

print(operator.add(-1.0, 1.0))
print(operator.add(0, 0))
print(operator.add(12, 2))
--[[test
0
0
14
--test]]

print(operator.div(10, 2))
print(operator.div(10, 3))
print(operator.div(-10, 3))
--[[test
5
3.3333333333333
-3.3333333333333
--test]]

print(operator.floordiv(10, 3))
print(operator.floordiv(11, 3))
print(operator.floordiv(12, 3))
print(operator.floordiv(-10, 3))
print(operator.floordiv(-11, 3))
print(operator.floordiv(-12, 3))
--[[test
3
3
4
-4
-4
-4
--test]]

print(operator.intdiv(10, 3))
print(operator.intdiv(11, 3))
print(operator.intdiv(12, 3))
print(operator.intdiv(-10, 3))
print(operator.intdiv(-11, 3))
print(operator.intdiv(-12, 3))
--[[test
3
3
4
-3
-3
-4
--test]]

print(operator.truediv(10, 3))
print(operator.truediv(11, 3))
print(operator.truediv(12, 3))
print(operator.truediv(-10, 3))
print(operator.truediv(-11, 3))
print(operator.truediv(-12, 3))
--[[test
3.3333333333333
3.6666666666667
4
-3.3333333333333
-3.6666666666667
-4
--test]]

print(operator.mod(10, 2))
print(operator.mod(10, 3))
print(operator.mod(-10, 3))
--[[test
0
1
2
--test]]

print(operator.mul(10, 0.1))
print(operator.mul(0, 0))
print(operator.mul(-1, -1))
--[[test
1
0
1
--test]]

print(operator.neq(1))
print(operator.neq(0) == 0)
print(operator.neq(-0) == 0)
print(operator.neq(-1))
--[[test
-1
true
true
1
--test]]

print(operator.unm(1))
print(operator.unm(0) == 0)
print(operator.unm(-0) == 0)
print(operator.unm(-1))
--[[test
-1
true
true
1
--test]]

print(operator.pow(2, 3))
print(operator.pow(0, 10))
print(operator.pow(2, 0))
--[[test
8
0
1
--test]]

print(operator.sub(2, 3))
print(operator.sub(0, 10))
print(operator.sub(2, 2))
--[[test
-1
-10
0
--test]]

--------------------------------------------------------------------------------
-- String operators
--------------------------------------------------------------------------------

print(operator.concat("aa", "bb"))
print(operator.concat("aa", ""))
print(operator.concat("", "bb"))
--[[test
aabb
aa
bb
--test]]

print(operator.len(""))
print(operator.len("ab"))
print(operator.len("abcd"))
--[[test
0
2
4
--test]]

print(operator.length(""))
print(operator.length("ab"))
print(operator.length("abcd"))
--[[test
0
2
4
--test]]

----------------------------------------------------------------------------
-- Logical operators
----------------------------------------------------------------------------

print(operator.land(true, true))
print(operator.land(true, false))
print(operator.land(false, true))
print(operator.land(false, false))
print(operator.land(1, 0))
print(operator.land(0, 1))
print(operator.land(1, 1))
print(operator.land(0, 0))
--[[test
true
false
false
false
0
1
1
0
--test]]

print(operator.lor(true, true))
print(operator.lor(true, false))
print(operator.lor(false, true))
print(operator.lor(false, false))
print(operator.lor(1, 0))
print(operator.lor(0, 1))
print(operator.lor(1, 1))
print(operator.lor(0, 0))
--[[test
true
true
true
false
1
0
1
0
--test]]

print(operator.lnot(true))
print(operator.lnot(false))
print(operator.lor(1))
print(operator.lor(0))
--[[test
false
true
1
0
--test]]

print(operator.truth(true))
print(operator.truth(false))
print(operator.truth(1))
print(operator.truth(0))
print(operator.truth(nil))
print(operator.truth(""))
print(operator.truth({}))
--[[test
true
false
true
true
false
true
true
--test]]


================================================
FILE: tests/reducing.lua
================================================
--------------------------------------------------------------------------------
-- foldl
--------------------------------------------------------------------------------

print(foldl(function(acc, x) return acc + x end, 0, range(5)))
--[[test
15
--test]]

print(foldl(operator.add, 0, range(5)))
--[[test
15
--test]]

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

print(reduce == foldl) -- an alias
--[[test
true
--test]]

--------------------------------------------------------------------------------
-- length
--------------------------------------------------------------------------------

print(length({"a", "b", "c", "d", "e"}))
--[[test
5
--test]]

print(length({}))
--[[test
0
--test]]

print(length(range(0)))
--[[test
0
--test]]

-- gh-55: consider input iterator state in array/string optimizations
print(length(drop_n(3, {"a", "b", "c", "d", "e"})))
--[[test
2
--test]]

-- gh-55: consider input iterator state in array/string optimizations
print(length(drop_n(3, "abcdef")))
--[[test
3
--test]]


--------------------------------------------------------------------------------
-- is_null
--------------------------------------------------------------------------------

print(is_null({"a", "b", "c", "d", "e"}))
--[[test
false
--test]]

print(is_null({}))
--[[test
true
--test]]

print(is_null(range(0)))
--[[test
true
--test]]

local gen, init, state = range(5)
print(is_null(gen, init, state))
dump(gen, init, state)
--[[test
false
1
2
3
4
5
--test]]

--------------------------------------------------------------------------------
-- is_prefix_of
--------------------------------------------------------------------------------

print(is_prefix_of({"a"}, {"a", "b", "c"}))
--[[test
true
--test]]

print(is_prefix_of({}, {"a", "b", "c"}))
--[[test
true
--test]]

print(is_prefix_of({}, {}))
--[[test
true
--test]]

print(is_prefix_of({"a"}, {}))
--[[test
false
--test]]

print(is_prefix_of({"a"}, {"b"}))
--[[test
false
--test]]

print(is_prefix_of({"a", "b"}, {"a", "c"}))
--[[test
false
--test]]

print(is_prefix_of({"a", "b", "c"}, {"a", "b"}))
--[[test
false
--test]]

print(is_prefix_of(range(5), range(6)))
--[[test
true
--test]]

print(is_prefix_of(range(6), range(5)))
--[[test
false
--test]]

print(is_prefix_of(range(15), range(15)))
--[[test
true
--test]]

print(is_prefix_of(range(21), range(20)))
--[[test
false
--test]]

print(is_prefix_of(range(15), range(20)))
--[[test
true
--test]]

print(is_prefix_of(
    range(3):map(function(v) return v < 3 and v or nil end), -- {1, 2, nil}
    { 1, 2 }
))
--[[test
false
--test]]

local function range_once(stop)
    local v = 0
    return function()
        v = v + 1
        if v <= stop then
            return v, v
        end

        return nil
    end
end

local prefix = range_once(2) -- null expected
local iterator = range_once(3) -- trimmed prefix expected

print(is_prefix_of(wrap(prefix), wrap(iterator)))
print(is_null(prefix))
print((iterator()))
--[[test
true
true
3
--test]]

--------------------------------------------------------------------------------
-- all
--------------------------------------------------------------------------------

print(all(function(x) return x end, {true, true, true, true}))
--[[test
true
--test]]

print(all(function(x) return x end, {true, true, true, false}))
--[[test
false
--test]]

print(all(function(x) return x end, {}))
--[[test
true
--test]]

print(every == all) -- an alias
--[[test
true
--test]]

--------------------------------------------------------------------------------
-- any
--------------------------------------------------------------------------------

print(any(function(x) return x end, {false, false, false, false}))
--[[test
false
--test]]

print(any(function(x) return x end, {false, false, false, true}))
--[[test
true
--test]]

print(any(function(x) return x end, {}))
--[[test
false
--test]]

print(some == any) -- an alias
--[[test
true
--test]]

--------------------------------------------------------------------------------
-- sum
--------------------------------------------------------------------------------

print(sum(range(1, 5)))
--[[test
15
--test]]

print(sum(range(1, 5, 0.5)))
--[[test
27
--test]]

print(sum(range(0)))
--[[test
0
--test]]

--------------------------------------------------------------------------------
-- product
--------------------------------------------------------------------------------

print(product(range(1, 5)))
--[[test
120
--test]]

print(product(range(1, 5, 0.5)))
--[[test
7087.5
--test]]

print(product(range(0)))
--[[test
1
--test]]


--------------------------------------------------------------------------------
-- min
--------------------------------------------------------------------------------

print(min(range(1, 10, 1)))
--[[test
1
--test]]

print(min({"f", "d", "c", "d", "e"}))
--[[test
c
--test]]

print(min({}))
--[[test
error: min: iterator is empty
--test]]

print(minimum == min) -- an alias
--[[test
true
--test]]

--------------------------------------------------------------------------------
-- min_by
--------------------------------------------------------------------------------

function min_cmp(a, b) if -a < -b then return a else return b end end
--[[test
--test]]

print(min_by(min_cmp, range(1, 10, 1)))
--[[test
10
--test]]

print(min_by(min_cmp, {}))
--[[test
error: min: iterator is empty
--test]]

print(minimum_by == min_by) -- an alias
--[[test
true
--test]]

--------------------------------------------------------------------------------
-- max
--------------------------------------------------------------------------------

print(max(range(1, 10, 1)))
--[[test
10
--test]]

print(max({"f", "d", "c", "d", "e"}))
--[[test
f
--test]]

print(max({}))
--[[test
error: max: iterator is empty
--test]]

print(maximum == max) -- an alias
--[[test
true
--test]]

--------------------------------------------------------------------------------
-- max_by
--------------------------------------------------------------------------------

function max_cmp(a, b) if -a > -b then return a else return b end end
--[[test
--test]]

print(max_by(max_cmp, range(1, 10, 1)))
--[[test
1
--test]]

print(max_by(max_cmp, {}))
--[[test
error: max: iterator is empty
--test]]

print(maximum_by == max_by) -- an alias
--[[test
true
--test]]


================================================
FILE: tests/runtest
================================================
#!/usr/bin/env lua

package.path = "../?.lua;"..package.path
require "fun" ()
function dump(gen, init, state) each(print, gen, init, state) end

-- Check if state is preserved
function dump_state(gen, init, state)
    for s in gen, init, state do
        print(s)
    end
end

local unpack = rawget(table, "unpack") or unpack
local loadstring = rawget(_G, "loadstring") or load

function file_print(file, ...)
    local n, i = select("#",...)
    for i=1,n do
        local x = select(i, ...)
        if type(x) == "number" and math.floor(x) == math.ceil(x) then
            -- A special hack for Lua 5.3: remove .0 for integer
            x = string.match(select(i,...), '^-?%d+')
        end
        file:write(tostring(x))
        if i~=n then
            file:write(' ')
        end
    end
    file:write('\n')
end

local globals = {}
setmetatable(_G, {
    __newindex = function(t,k,v)
        local info = debug.getinfo(2, "S")
        if info.short_src:sub(1,7) ~= '[string' then
            local file = info.short_src
            local func = debug.getinfo(2, "n").name or ""
            local line = info.linedefined
            globals[file..':'..line..':'..k] = {file, line, func, k}
        end
        rawset(t, k, v)
    end
})

local function process(test_name)
    io.write("Testing ", test_name, "\n")
    local new_name = test_name..".new"
    local test_file = io.open(test_name, 'r')
    local content = test_file:read("*a");
    test_file:close()

    local new_file = io.open(new_name, 'w')

    local prev_print = print
    print = function(...) file_print(new_file, ...) end

    io.flush()
    local expr
    for expr in content:gmatch("(.-)%s*--%[%[test.-test%]%]") do
        new_file:write(expr)
        new_file:write("\n--[[test\n")
        local res, err = loadstring(expr)
        if res then
            res, err = pcall(res, expr)
        end
        if not res then
            new_file:write('error: ', err:match(".-:%d+:%s*(.*)"), "\n")
        end
        new_file:write("--test]]")
    end
    new_file:write("\n")
    new_file:close()

    print = prev_print

    local r = os.execute(string.format('diff -U4 "%s" "%s" 2>&1',
        test_name, new_name))
    if r then
        os.remove(new_name)
        return true
    else
        return false
    end
end

if #arg <= 0 then
    io.write("Usage: runtest *.lua", "\n")
    os.exit(1)
end

local failed, i = {}
for i=1,#arg,1 do
    local test_name = arg[i]
    if not process(test_name) then
        table.insert(failed, test_name)
    end
end

if #failed > 0 then
    io.write("\n")
    io.write("Failed tests:", "\n")
    for _k,test_name in ipairs(failed) do
        io.write("   ", test_name, "\n")
    end
    io.write("\n", "Please review *.new files and update tests", "\n")
end

if next(globals) then
    io.write("\n")
    io.write("Some global variables have been declared by mistake:", "\n")
    for k, pollution in pairs(globals) do
        local file, line, func, var = unpack(pollution)
        io.write(file..":"..line.." function "..func.."() = var '"..var.."'", "\n")
    end
    io.write("\n", "Please declare them with the local statement", "\n")
elseif #failed == 0 then
    io.write("All tests have passed!", "\n")
    os.exit(0)
end


================================================
FILE: tests/slicing.lua
================================================
--------------------------------------------------------------------------------
-- nth
--------------------------------------------------------------------------------

print(nth(2, range(5)))
--[[test
2
--test]]

print(nth(10, range(5)))
--[[test
nil
--test]]

print(nth(2, range(0)))
--[[test
nil
--test]]

print(nth(2, {"a", "b", "c", "d", "e"}))
--[[test
b
--test]]

print(nth(2, enumerate({"a", "b", "c", "d", "e"})))
--[[test
2 b
--test]]

print(nth(1, "abcdef"))
--[[test
a
--test]]

print(nth(2, "abcdef"))
--[[test
b
--test]]

print(nth(6, "abcdef"))
--[[test
f
--test]]

print(nth(0, "abcdef"))
--[[test
error: invalid first argument to nth
--test]]

print(nth(7, "abcdef"))
--[[test
nil
--test]]

-- gh-55: consider input iterator state in array/string optimizations
print(nth(1, drop_n(3, {"a", "b", "c", "d", "e"})))
--[[test
d
--test]]

-- gh-55: consider input iterator state in array/string optimizations
print(nth(1, drop_n(3, "abcdef")))
--[[test
d
--test]]

--------------------------------------------------------------------------------
-- head
--------------------------------------------------------------------------------

print(head({"a", "b", "c", "d", "e"}))
--[[test
a
--test]]

print(head({}))
--[[test
error: head: iterator is empty
--test]]

print(head(range(0)))
--[[test
error: head: iterator is empty
--test]]

print(head(enumerate({"a", "b"})))
--[[test
1 a
--test]]

print(car == head) -- an alias
--[[test
true
--test]]

--------------------------------------------------------------------------------
-- tail
--------------------------------------------------------------------------------

dump(tail({"a", "b", "c", "d", "e"}))
--[[test
b
c
d
e
--test]]

dump(tail({}))
--[[test
--test]]

dump(tail(range(0)))
--[[test
--test]]

dump(tail(enumerate({"a", "b"})))
--[[test
2 b
--test]]

print(cdr == tail) -- an alias
--[[test
true
--test]]

dump_state(tail(ipairs({"a", "b", "c", "d", "e"})))
--[[test
2
3
4
5
--test]]


--------------------------------------------------------------------------------
-- take_n
--------------------------------------------------------------------------------

dump(take_n(0, duplicate(48)))
--[[test
--test]]

dump(take_n(5, range(0)))
--[[test
--test]]

dump(take_n(1, duplicate(48)))
--[[test
48
--test]]

dump(take_n(5, duplicate(48)))
--[[test
48
48
48
48
48
--test]]

dump(take_n(5, enumerate(duplicate('x'))))
--[[test
1 x
2 x
3 x
4 x
5 x
--test]]

--------------------------------------------------------------------------------
-- take_while
--------------------------------------------------------------------------------

dump(take_while(function(x) return x < 5 end, range(10)))
--[[test
1
2
3
4
--test]]

dump(take_while(function(x) return x < 5 end, range(0)))
--[[test
--test]]

dump(take_while(function(x) return x > 100 end, range(10)))
--[[test
--test]]

dump(take_while(function(i, a) return i ~=a end, enumerate({5, 2, 1, 3, 4})))
--[[test
1 5
--test]]

dump_state(take_while(function(x) return x < 3 end, ipairs({0, 0, 0, 2, 3})))
--[[test
1
2
3
4
--test]]

--------------------------------------------------------------------------------
-- take
--------------------------------------------------------------------------------

dump(take(function(x) return x < 5 end, range(10)))
--[[test
1
2
3
4
--test]]

dump(take(5, duplicate(48)))
--[[test
48
48
48
48
48
--test]]

--------------------------------------------------------------------------------
-- drop_n
--------------------------------------------------------------------------------

dump(drop_n(5, range(10)))
--[[test
6
7
8
9
10
--test]]

dump(drop_n(0, range(5)))
--[[test
1
2
3
4
5
--test]]

dump(drop_n(5, range(0)))
--[[test
--test]]

dump(drop_n(2, enumerate({'a', 'b', 'c', 'd', 'e'})))
--[[test
3 c
4 d
5 e
--test]]

dump_state(drop_n(3, ipairs({'a', 'b', 'c', 'd', 'e'})))
--[[test
4
5
--test]]

--------------------------------------------------------------------------------
-- drop_while
--------------------------------------------------------------------------------

dump(drop_while(function(x) return x < 5 end, range(10)))
--[[test
5
6
7
8
9
10
--test]]

dump(drop_while(function(x) return x < 5 end, range(0)))
--[[test
--test]]

dump(drop_while(function(x) return x > 100 end, range(10)))
--[[test
1
2
3
4
5
6
7
8
9
10
--test]]

dump(drop_while(function(i, a) return i ~=a end, enumerate({5, 2, 1, 3, 4})))
--[[test
2 2
3 1
4 3
5 4
--test]]

dump(drop_while(function(i, a) return i ~=a end,
    zip({1, 2, 3, 4, 5}, {5, 4, 3, 2, 1})))
--[[test
3 3
4 2
5 1
--test]]

dump_state(drop_while(function(x) return x < 5 end, ipairs({0, 0, 4, 6, 2})))
--[[test
4
5
--test]]

--------------------------------------------------------------------------------
-- drop
--------------------------------------------------------------------------------

dump(drop(5, range(10)))
--[[test
6
7
8
9
10
--test]]

dump(drop(function(x) return x < 5 end, range(10)))
--[[test
5
6
7
8
9
10
--test]]


--------------------------------------------------------------------------------
-- span
--------------------------------------------------------------------------------

dump(zip(span(function(x) return x < 5 end, range(10))))
--[[test
1 5
2 6
3 7
4 8
--test]]

dump(zip(span(5, range(10))))
--[[test
1 6
2 7
3 8
4 9
5 10
--test]]

dump(zip(span(function(x) return x < 5 end, range(0))))
--[[test
--test]]

dump(zip(span(function(x) return x < 5 end, range(5))))
--[[test
1 5
--test]]

print(split == span) -- an alias
--[[test
true
--test]]

print(split_at == span) -- an alias
--[[test
true
--test]]


================================================
FILE: tests/stateful.lua
================================================
-- compatibility with Lua 5.1/5.2
local unpack = rawget(table, "unpack") or unpack

function gen_stateful_iter(values)
    local i = 1
    local gen = function(_param, values)
        if i > #values then
            return nil
        end
        local t = values[i]
        i = i + 1
        if type(t) == 'table' then
            return values, unpack(t, 1, table.maxn(t))
        else
            return values, t
        end
    end
    return iter(gen, nil, values)
end

--------------------------------------------------------------------------------
-- drop_while
--------------------------------------------------------------------------------

-- Simple test
dump(gen_stateful_iter({1, 2, 3, 4, 5, 6, 5, 4, 3}):drop_while(function(x) return x < 5 end))
--[[test
5
6
5
4
3
--test]]

-- Multireturn
dump(gen_stateful_iter({{1, 10}, {3, 30}, {5, 50}, {6, 60}, {3, 20}}):drop_while(function(x) return x < 5 end))
--[[test
5 50
6 60
3 20
--test]]

-- Multireturn with nil
dump(gen_stateful_iter({{1, nil, 10}, {3, nil, 30}, {5, nil, 50}, {6, nil, 60}, {3, nil, 20}}):drop_while(function(x) return x < 5 end))
--[[test
5 nil 50
6 nil 60
3 nil 20
--test]]

-- Multireturn with condition on second returned value
dump(gen_stateful_iter({{0, 1}, {0, 3}, {0, 5}, {0, 4}}):drop_while(function(x, y) return y < 5 end))
--[[test
0 5
0 4
--test]]

-- Empty iterator
dump(gen_stateful_iter({}):drop_while(function(x) return x < 5 end))
--[[test
--test]]

-- Always false
dump(gen_stateful_iter({1, 2, 3, 4, 5}):drop_while(function(x) return x > 100 end))
--[[test
1
2
3
4
5
--test]]


================================================
FILE: tests/transformations.lua
================================================
--------------------------------------------------------------------------------
-- map
--------------------------------------------------------------------------------

fun = function(...) return 'map', ... end

dump(map(fun, range(0)))
--[[test
--test]]


dump(map(fun, range(4)))
--[[test
map 1
map 2
map 3
map 4
--test]]

dump(map(fun, enumerate({"a", "b", "c", "d", "e"})))
--[[test
map 1 a
map 2 b
map 3 c
map 4 d
map 5 e
--test]]

dump(map(function(x) return 2 * x end, range(4)))
--[[test
2
4
6
8
--test]]

fun = nil
--[[test
--test]]

--------------------------------------------------------------------------------
-- enumerate
--------------------------------------------------------------------------------

dump(enumerate({"a", "b", "c", "d", "e"}))
--[[test
1 a
2 b
3 c
4 d
5 e
--test]]

dump(enumerate(enumerate(enumerate({"a", "b", "c", "d", "e"}))))
--[[test
1 1 1 a
2 2 2 b
3 3 3 c
4 4 4 d
5 5 5 e
--test]]

dump(enumerate(zip({"one", "two", "three", "four", "five"},
    {"a", "b", "c", "d", "e"})))
--[[test
1 one a
2 two b
3 three c
4 four d
5 five e
--test]]

--------------------------------------------------------------------------------
-- intersperse
--------------------------------------------------------------------------------

dump(intersperse("x", {}))

dump(intersperse("x", {"a", "b", "c", "d", "e"}))
--[[test
a
x
b
x
c
x
d
x
e
x
--test]]

dump(intersperse("x", {"a", "b", "c", "d", "e", "f"}))
--[[test
a
x
b
x
c
x
d
x
e
x
f
x
--test]]
Download .txt
gitextract_diaikeab/

├── .gitignore
├── .travis.yml
├── CONTRIBUTING.md
├── COPYING.md
├── HACKING.md
├── README.md
├── debian/
│   ├── .gitignore
│   ├── changelog
│   ├── compat
│   ├── control
│   ├── copyright
│   ├── lua-fun.docs
│   ├── lua5.1.dh-lua.conf
│   ├── patches/
│   │   └── series
│   ├── rules
│   ├── source/
│   │   └── format
│   └── watch
├── doc/
│   ├── .gitignore
│   ├── Makefile
│   ├── _static/
│   │   └── .keep
│   ├── _templates/
│   │   └── layout.html
│   ├── about.rst
│   ├── basic.rst
│   ├── compositions.rst
│   ├── conf.py
│   ├── filtering.rst
│   ├── generators.rst
│   ├── getting_started.rst
│   ├── index.rst
│   ├── indexing.rst
│   ├── intro.rst
│   ├── operators.rst
│   ├── reducing.rst
│   ├── reference.rst
│   ├── slicing.rst
│   ├── transformations.rst
│   └── under_the_hood.rst
├── fun-scm-1.rockspec
├── fun.lua
├── rpm/
│   └── lua-fun.spec
└── tests/
    ├── .gitignore
    ├── basic.lua
    ├── compositions.lua
    ├── filtering.lua
    ├── generators.lua
    ├── indexing.lua
    ├── operators.lua
    ├── reducing.lua
    ├── runtest
    ├── slicing.lua
    ├── stateful.lua
    └── transformations.lua
Condensed preview — 52 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (145K chars).
[
  {
    "path": ".gitignore",
    "chars": 28,
    "preview": "*~\ntemp/\nfun.lua.c\n5.?-fun/\n"
  },
  {
    "path": ".travis.yml",
    "chars": 1744,
    "preview": "sudo: false\nlanguage: C\nservices:\n  - docker\n\nenv:\n    global:\n      - PRODUCT=lua-fun\n    matrix:\n      - OS=el DIST=7\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 478,
    "preview": "Contributing\n============\n\nWe'd love for you to contribute to the project and make **Lua Fun** even better\nthan it is to"
  },
  {
    "path": "COPYING.md",
    "chars": 1292,
    "preview": "Copying\n=======\n\n**Lua Fun** source codes, logo and documentation are distributed under the\n**[MIT/X11 License]** - same"
  },
  {
    "path": "HACKING.md",
    "chars": 204,
    "preview": "# Hacking\n\n## Build documentation\n\nBuild and open in a Web browser:\n\n```sh\n$ cd doc\n$ make html\n$ xdg-open _build/html/i"
  },
  {
    "path": "README.md",
    "chars": 3742,
    "preview": "Lua Functional\n==============\n\n<img src=\"/doc/logo.png\" align=\"right\" width=\"174px\" height=\"144px\" />\n\n**Lua Fun** is a "
  },
  {
    "path": "debian/.gitignore",
    "chars": 67,
    "preview": "lua-fun/\ntmp/\ntrash\nfiles\nlua_versions\n*.install\n*.substvars\n*.log\n"
  },
  {
    "path": "debian/changelog",
    "chars": 156,
    "preview": "lua-fun (0.1.3-1) unstable; urgency=medium\n\n  * Initial release. (Closes: #811482)\n\n -- Roman Tsisyk <roman@tarantool.or"
  },
  {
    "path": "debian/compat",
    "chars": 2,
    "preview": "9\n"
  },
  {
    "path": "debian/control",
    "chars": 784,
    "preview": "Source: lua-fun\nSection: interpreters\nPriority: optional\nMaintainer: Roman Tsisyk <roman@tarantool.org>\nBuild-Depends: d"
  },
  {
    "path": "debian/copyright",
    "chars": 1597,
    "preview": "Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/\nUpstream-Name: luafun\nUpstream-Contact: Roman "
  },
  {
    "path": "debian/lua-fun.docs",
    "chars": 10,
    "preview": "README.md\n"
  },
  {
    "path": "debian/lua5.1.dh-lua.conf",
    "chars": 84,
    "preview": "PKG_NAME=fun\nLUA_MODNAME=fun\nLUA_SOURCES=fun.lua\nLUA_TEST=tests/runtest tests/*.lua\n"
  },
  {
    "path": "debian/patches/series",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "debian/rules",
    "chars": 357,
    "preview": "#!/usr/bin/make -f\n\nVERSION  := $(shell dpkg-parsechangelog|grep ^Version|awk '{print $$2}')\nUVERSION := $(shell echo $("
  },
  {
    "path": "debian/source/format",
    "chars": 12,
    "preview": "3.0 (quilt)\n"
  },
  {
    "path": "debian/watch",
    "chars": 291,
    "preview": "# test this watch file using:\n# uscan --watchfile debian/watch --upstream-version 0.0.1 --package lua-fun\n# https://wiki"
  },
  {
    "path": "doc/.gitignore",
    "chars": 7,
    "preview": "_build\n"
  },
  {
    "path": "doc/Makefile",
    "chars": 634,
    "preview": "# Minimal makefile for Sphinx documentation\n#\n\n# You can set these variables from the command line, and also\n# from the "
  },
  {
    "path": "doc/_static/.keep",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "doc/_templates/layout.html",
    "chars": 511,
    "preview": "{% extends \"!layout.html\" %}\n\n{% block footer %}\n{{ super() }}\n    <script type=\"text/javascript\">\n(function(i,s,o,g,r,a"
  },
  {
    "path": "doc/about.rst",
    "chars": 1707,
    "preview": "About\n=====\n\nCredits\n-------\n\nAn initial prototype was designed and enginered in one evening by Roman Tsisyk.\nAfter that"
  },
  {
    "path": "doc/basic.rst",
    "chars": 3579,
    "preview": "Basic Functions\n===============\n\n.. currentmodule:: fun\n\nThe section contains functions to create iterators from Lua obj"
  },
  {
    "path": "doc/compositions.rst",
    "chars": 3154,
    "preview": "Compositions\n============\n\n.. currentmodule:: fun\n\n.. function:: zip(...)\n              iterator1:zip(iterator2, iterato"
  },
  {
    "path": "doc/conf.py",
    "chars": 2490,
    "preview": "# Configuration file for the Sphinx documentation builder.\n#\n# This file only contains a selection of the most common op"
  },
  {
    "path": "doc/filtering.rst",
    "chars": 2953,
    "preview": "Filtering\n=========\n\n.. currentmodule:: fun\n\nThis section contains functions to filter values during iteration.\n\n.. func"
  },
  {
    "path": "doc/generators.rst",
    "chars": 4943,
    "preview": "Generators\n==========\n\n.. currentmodule:: fun\n\nThis section contains a number of useful generators modeled after Standar"
  },
  {
    "path": "doc/getting_started.rst",
    "chars": 5944,
    "preview": "Getting Started\n===============\n\nPlease jump to `Using the Library`_ section if you are familiar with Lua and\nLuaJIT.\n\n."
  },
  {
    "path": "doc/index.rst",
    "chars": 378,
    "preview": ".. _library-index:\n\n###############################\n  Lua Functional Library\n###############################\n\n:Release: "
  },
  {
    "path": "doc/indexing.rst",
    "chars": 1653,
    "preview": "Indexing\n========\n\n.. currentmodule:: fun\n\nThis section contains functions to find elements by its values.\n\n.. function:"
  },
  {
    "path": "doc/intro.rst",
    "chars": 2159,
    "preview": "Introduction\n============\n\n.. currentmodule:: fun\n\n**Lua Fun** is a high-performance functional programming library\ndesi"
  },
  {
    "path": "doc/operators.rst",
    "chars": 3631,
    "preview": "Operators\n=========\n\n.. module:: fun.operator\n\nThis auxiliary module exports a set of Lua operators as intrinsic functio"
  },
  {
    "path": "doc/reducing.rst",
    "chars": 7240,
    "preview": "Reducing\n========\n\n.. currentmodule:: fun\n\nThe section contains functions to analyze iteration values and recombine\nthro"
  },
  {
    "path": "doc/reference.rst",
    "chars": 215,
    "preview": "API Reference\n=============\n\n.. module:: fun\n\n.. toctree::\n\n   basic.rst\n   generators.rst\n   slicing.rst\n   indexing.rs"
  },
  {
    "path": "doc/slicing.rst",
    "chars": 5630,
    "preview": "Slicing\n=======\n\n.. currentmodule:: fun\n\nThis section contains functions to make subsequences from iterators.\n\nBasic\n---"
  },
  {
    "path": "doc/transformations.rst",
    "chars": 1802,
    "preview": "Transformations\n===============\n\n.. currentmodule:: fun\n\n.. function:: map(fun, gen, param, state)\n              iterato"
  },
  {
    "path": "doc/under_the_hood.rst",
    "chars": 5793,
    "preview": "Under the Hood\n==============\n\n.. currentmodule:: fun\n\nThe section sheds some light on the internal library structure an"
  },
  {
    "path": "fun-scm-1.rockspec",
    "chars": 886,
    "preview": "package = \"fun\"\nversion = \"scm-1\"\n\nsource = {\n    url = \"git+https://github.com/luafun/luafun.git\",\n}\n\ndescription = {\n "
  },
  {
    "path": "fun.lua",
    "chars": 29691,
    "preview": "---\n--- Lua Fun - a high-performance functional programming library for LuaJIT\n---\n--- Copyright (c) 2013-2017 Roman Tsi"
  },
  {
    "path": "rpm/lua-fun.spec",
    "chars": 2187,
    "preview": "%define luaver 5.3\n%define luapkgdir %{_datadir}/lua/%{luaver}\n# LuaJIT is compatible with Lua 5.1 and uses the same dir"
  },
  {
    "path": "tests/.gitignore",
    "chars": 6,
    "preview": "*.new\n"
  },
  {
    "path": "tests/basic.lua",
    "chars": 4748,
    "preview": "--------------------------------------------------------------------------------\n-- iter\n-------------------------------"
  },
  {
    "path": "tests/compositions.lua",
    "chars": 2697,
    "preview": "--------------------------------------------------------------------------------\n-- zip\n--------------------------------"
  },
  {
    "path": "tests/filtering.lua",
    "chars": 2438,
    "preview": "--------------------------------------------------------------------------------\n-- filter\n-----------------------------"
  },
  {
    "path": "tests/generators.lua",
    "chars": 3254,
    "preview": "--------------------------------------------------------------------------------\n-- range\n------------------------------"
  },
  {
    "path": "tests/indexing.lua",
    "chars": 1319,
    "preview": "--------------------------------------------------------------------------------\n-- index\n------------------------------"
  },
  {
    "path": "tests/operators.lua",
    "chars": 4619,
    "preview": "--\n-- All these functions are fully covered by Lua tests.\n-- This test just checks that all functions were defined corre"
  },
  {
    "path": "tests/reducing.lua",
    "chars": 6350,
    "preview": "--------------------------------------------------------------------------------\n-- foldl\n------------------------------"
  },
  {
    "path": "tests/runtest",
    "chars": 3250,
    "preview": "#!/usr/bin/env lua\n\npackage.path = \"../?.lua;\"..package.path\nrequire \"fun\" ()\nfunction dump(gen, init, state) each(print"
  },
  {
    "path": "tests/slicing.lua",
    "chars": 5556,
    "preview": "--------------------------------------------------------------------------------\n-- nth\n--------------------------------"
  },
  {
    "path": "tests/stateful.lua",
    "chars": 1577,
    "preview": "-- compatibility with Lua 5.1/5.2\nlocal unpack = rawget(table, \"unpack\") or unpack\n\nfunction gen_stateful_iter(values)\n "
  },
  {
    "path": "tests/transformations.lua",
    "chars": 1474,
    "preview": "--------------------------------------------------------------------------------\n-- map\n--------------------------------"
  }
]

About this extraction

This page contains the full source code of the rtsisyk/luafun GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 52 files (132.2 KB), approximately 39.3k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!