[
  {
    "path": ".gitignore",
    "content": "*~\ntemp/\nfun.lua.c\n5.?-fun/\n"
  },
  {
    "path": ".travis.yml",
    "content": "sudo: false\nlanguage: C\nservices:\n  - docker\n\nenv:\n    global:\n      - PRODUCT=lua-fun\n    matrix:\n      - OS=el DIST=7\n      - OS=fedora DIST=24\n      - OS=fedora DIST=25\n      - OS=ubuntu DIST=xenial\n      - OS=ubuntu DIST=yakkety\n      - OS=debian DIST=stretch\n\nbefore_deploy:\n - git clone https://github.com/packpack/packpack.git packpack\n - ./packpack/packpack\n\ndeploy:\n  provider: packagecloud\n  username: ${PACKAGECLOUD_USER}\n  repository: ${PACKAGECLOUD_REPO}\n  token: ${PACKAGECLOUD_TOKEN}\n  dist: ${OS}/${DIST}\n  package_glob: build/*.{deb,rpm}\n  skip_cleanup: true\n  on:\n    branch: master\n    condition: -n \"${OS}\" && -n \"${DIST}\" && -n \"${PACKAGECLOUD_TOKEN}\"\n\nafter_deploy:\n # Prune old packages from PackageCloud, keep only the last two\n - pip install -r ./packpack/tools/requirements.txt\n - python ./packpack/tools/packagecloud prune ${PACKAGECLOUD_USER}/${PACKAGECLOUD_REPO} deb ${OS} ${DIST} --keep 2\n - python ./packpack/tools/packagecloud prune ${PACKAGECLOUD_USER}/${PACKAGECLOUD_REPO} rpm ${OS} ${DIST} --keep 2\n\ncache:\n  directories:\n  - $HOME/lua-5.3.2\n\naddons:\n  apt:\n    packages:\n      - lua5.1\n      - lua5.2\n      - luajit\n\n# Ubuntu Precise on Travis doesn't have lua5.3 package\ninstall:\n  - |\n    [ -e ${HOME}/lua-5.3.2/src/lua ] || (\\\n        wget http://www.lua.org/ftp/lua-5.3.2.tar.gz -c && \\\n        tar xzf lua-5.3.2.tar.gz -C ${HOME} && \\\n        make -j -C ${HOME}/lua-5.3.2 linux \\\n    )\n\nscript:\n  - cd tests\n  - LUAJIT=`echo /usr/bin/luajit* | cut -f 1 -d ' '`\n  - ${LUAJIT} -v\n  - ${LUAJIT} runtest *.lua\n  - lua5.1 -v\n  - lua5.1 runtest *.lua\n  - lua5.2 -v\n  - lua5.2 runtest *.lua\n  - LUA53=${HOME}/lua-5.3.2/src/lua\n  - ${LUA53} -v\n  - ${LUA53} runtest *.lua\n  - cd ..\n\nnotifications:\n  email: true\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "Contributing\n============\n\nWe'd love for you to contribute to the project and make **Lua Fun** even better\nthan it is today!\n\nFilling Issues\n---------------\n\nPlease file bugs reports and feature requests using [GitHub Issues].\n\n[GitHub Issues]: https://github.com/luafun/luafun/issues\n\nMaking Changes\n--------------\n\nIf you want to contribute code, please fork the project on [GitHub], make\nchanges in branch and send a pull request.\n\n[GitHub]: https://github.com/luafun/luafun\n"
  },
  {
    "path": "COPYING.md",
    "content": "Copying\n=======\n\n**Lua Fun** source codes, logo and documentation are distributed under the\n**[MIT/X11 License]** - same as Lua and LuaJIT.\n\nCopyright (c) 2013-2017 Roman Tsisyk <roman@tsisyk.com>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n\n[MIT/X11 License]: http://www.opensource.org/licenses/mit-license.php\n"
  },
  {
    "path": "HACKING.md",
    "content": "# 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/index.html\n```\n\nIt works with Sphinx 4.3.0 and likely will work with newer versions.\n"
  },
  {
    "path": "README.md",
    "content": "Lua Functional\n==============\n\n<img src=\"/doc/logo.png\" align=\"right\" width=\"174px\" height=\"144px\" />\n\n**Lua Fun** is a high-performance functional programming library for [Lua]\ndesigned with [LuaJIT's trace compiler][LuaJIT] in mind.\n\nLua Fun provides a set of more than 50 programming primitives typically\nfound in languages like Standard ML, Haskell, Erlang, JavaScript, Python and\neven Lisp. High-order functions such as ``map``, ``filter``, ``reduce``,\n``zip``, etc., make it easy to **write simple and efficient functional code**.\n\nLet's see an example:\n\n```lua\n> -- Functional style\n> require \"fun\" ()\n> -- calculate sum(x for x^2 in 1..n)\n> n = 100\n> print(reduce(operator.add, 0, map(function(x) return x^2 end, range(n))))\n328350\n\n> -- Object-oriented style\n> local fun = require \"fun\"\n> -- calculate sum(x for x^2 in 1..n)\n> print(fun.range(n):map(function(x) return x^2 end):reduce(operator.add, 0))\n328350\n```\n\n**Lua Fun** takes full advantage of the innovative **tracing JIT compiler**\nto achieve transcendental performance on nested functional expressions.\nFunctional compositions and high-order functions can be translated into\n**efficient machine code**. Can you believe it? Just try to run the example\nabove with ``luajit -jdump`` and see what happens:\n\n```asm\n-- skip some initialization code --\n->LOOP:\n0bcaffd0  movaps xmm5, xmm7\n0bcaffd3  movaps xmm7, xmm1\n0bcaffd6  addsd xmm7, xmm5\n0bcaffda  ucomisd xmm7, xmm0\n0bcaffde  jnb 0x0bca0024        ->5\n0bcaffe4  movaps xmm5, xmm7\n0bcaffe7  mulsd xmm5, xmm5\n0bcaffeb  addsd xmm6, xmm5\n0bcaffef  jmp 0x0bcaffd0        ->LOOP\n---- TRACE 1 stop -> loop\n```\n\nThe functional chain above was translated by LuaJIT to (!) **one machine loop**\ncontaining just 10 CPU assembly instructions without CALL. Unbelievable!\n\nReadable? Efficient? Can your Python/Ruby/V8 do better?\n\nStatus\n------\n\n**Lua Fun** is in an early alpha stage. The library fully\n[documented][Documentation] and covered with unit tests.\n\n[![Build Status](https://travis-ci.org/luafun/luafun.png)][Travis]\n\nLuaJIT 2.1 alpha is recommended. The library designed in mind of fact that\n[LuaJIT traces tail-, up- and down-recursion][LuaJIT-Recursion] and has a lot of\n[byte code optimizations][LuaJIT-Optimizations]. Lua 5.1-5.3 are also\nsupported.\n\nThis is **master** (development) branch. API may be changed without any special\nnotice. Please use **stable** branch for your production deployments.\nIf you still want to use **master**, please don't forget to grep `git log`\nfor *Incompatible API changes* message. Thanks!\n\nPlease check out [documentation][Documentation] for more information.\n\nMisc\n----\n\n**Lua Fun** is distributed under the [MIT/X11 License] -\n(same as Lua and LuaJIT).\n\nThe library was written to use with [Tarantool] - an efficient in-memory\nstore and an asynchronous Lua application server.\n\nSee Also\n--------\n\n* [Documentation]\n* [RockSpec]\n* [RPM/DEB packages](https://packagecloud.io/rtsisyk/master)\n* [Hacking]\n* lua-l@lists.lua.org\n* luajit@freelists.org\n* roman@tsisyk.com\n\n [Lua]: https://www.lua.org/\n [LuaJIT]: https://luajit.org/luajit.html\n [LuaJIT-Recursion]: http://lambda-the-ultimate.org/node/3851#comment-57679\n [LuaJIT-Optimizations]: http://wiki.luajit.org/Optimizations\n [MIT/X11 License]: https://opensource.org/licenses/MIT\n [Tarantool]: https://github.com/tarantool/tarantool\n [Getting Started]: https://luafun.github.io/getting_started.html\n [Documentation]: https://luafun.github.io/\n [Travis]: https://travis-ci.org/luafun/luafun\n [RockSpec]: https://raw.github.com/luafun/luafun/master/fun-scm-1.rockspec\n [Hacking]: HACKING.md\n\nPlease **\"Star\"** the project on GitHub to help it to survive! Thanks!\n\n*****\n\n**Lua Fun**. Simple, Efficient and Functional. In Lua. With JIT.\n"
  },
  {
    "path": "debian/.gitignore",
    "content": "lua-fun/\ntmp/\ntrash\nfiles\nlua_versions\n*.install\n*.substvars\n*.log\n"
  },
  {
    "path": "debian/changelog",
    "content": "lua-fun (0.1.3-1) unstable; urgency=medium\n\n  * Initial release. (Closes: #811482)\n\n -- Roman Tsisyk <roman@tarantool.org>  Mon, 18 Jan 2016 10:00:00 +0300\n"
  },
  {
    "path": "debian/compat",
    "content": "9\n"
  },
  {
    "path": "debian/control",
    "content": "Source: lua-fun\nSection: interpreters\nPriority: optional\nMaintainer: Roman Tsisyk <roman@tarantool.org>\nBuild-Depends: debhelper (>= 9), dh-lua (>= 19)\nStandards-Version: 3.9.6\nHomepage: https://github.com/luafun/luafun\nVcs-Git: git://github.com/luafun/luafun.git\nVcs-Browser: https://github.com/luafun/luafun\n\nPackage: lua-fun\nArchitecture: all\nDepends: ${misc:Depends}\nProvides: ${lua:Provides}\nXB-Lua-Versions: ${lua:Versions}\nDescription: High-performance functional programming library for Lua\n Lua Fun provides a set of more than 50 programming primitives typically\n found in languages like Standard ML, Haskell, Erlang, JavaScript, Python and\n even Lisp. High-order functions such as map, filter, reduce, zip, etc.,\n make it easy to write simple and efficient functional code.\n"
  },
  {
    "path": "debian/copyright",
    "content": "Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/\nUpstream-Name: luafun\nUpstream-Contact: Roman Tsisyk <roman@tsisyk.com>\nSource: https://github.com/luafun/luafun\n\nFiles: *\nCopyright: 2013-2017 Roman Tsisyk <roman@tsisyk.com>\nComment: In the Lua community this license is better known as \"MIT\".\n  Unfortunately other variants of this license are also known as \"MIT\".\n  To obtain a machine interpretable copyright file Debian prefers to name this\n  version of the MIT license using the non ambiguous term \"Expat\".\nLicense: Expat\n Permission is hereby granted, free of charge, to any person obtaining\n a copy of this software and associated documentation files (the\n “Software”), to deal in the Software without restriction, including\n without limitation the rights to use, copy, modify, merge, publish,\n distribute, sublicense, and/or sell copies of the Software, and to\n permit persons to whom the Software is furnished to do so, subject to\n the following conditions:\n .\n The above copyright notice and this permission notice shall be\n included in all copies or substantial portions of the Software.\n .\n THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,\n EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\n NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\n BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\n ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n SOFTWARE.\n"
  },
  {
    "path": "debian/lua-fun.docs",
    "content": "README.md\n"
  },
  {
    "path": "debian/lua5.1.dh-lua.conf",
    "content": "PKG_NAME=fun\nLUA_MODNAME=fun\nLUA_SOURCES=fun.lua\nLUA_TEST=tests/runtest tests/*.lua\n"
  },
  {
    "path": "debian/patches/series",
    "content": ""
  },
  {
    "path": "debian/rules",
    "content": "#!/usr/bin/make -f\n\nVERSION  := $(shell dpkg-parsechangelog|grep ^Version|awk '{print $$2}')\nUVERSION := $(shell echo $(VERSION)|sed 's/-[[:digit:]]\\+$$//')\n\n%:\n\tdh $@ --buildsystem=lua --with lua\n\ntarball: clean\n\t\ttar --exclude=.git --exclude=debian --exclude rpm \\\n\t\t\t--transform='s,^\\.,luafun-$(UVERSION),S' \\\n\t\t\t-czf ../luafun-$(UVERSION).orig.tar.gz .\n"
  },
  {
    "path": "debian/source/format",
    "content": "3.0 (quilt)\n"
  },
  {
    "path": "debian/watch",
    "content": "# test this watch file using:\n# uscan --watchfile debian/watch --upstream-version 0.0.1 --package lua-fun\n# https://wiki.debian.org/debian/watch#GitHub\nversion=3\nopts=filenamemangle=s/.+\\/v?(\\d\\S*)\\.tar\\.gz/luafun-$1\\.tar\\.gz/ \\\n  https://github.com/luafun/luafun/tags .*/v?(\\d\\S*)\\.tar\\.gz\n"
  },
  {
    "path": "doc/.gitignore",
    "content": "_build\n"
  },
  {
    "path": "doc/Makefile",
    "content": "# Minimal makefile for Sphinx documentation\n#\n\n# You can set these variables from the command line, and also\n# from the environment for the first two.\nSPHINXOPTS    ?=\nSPHINXBUILD   ?= sphinx-build\nSOURCEDIR     = .\nBUILDDIR      = _build\n\n# Put it first so that \"make\" without argument is like \"make help\".\nhelp:\n\t@$(SPHINXBUILD) -M help \"$(SOURCEDIR)\" \"$(BUILDDIR)\" $(SPHINXOPTS) $(O)\n\n.PHONY: help Makefile\n\n# Catch-all target: route all unknown targets to Sphinx using the new\n# \"make mode\" option.  $(O) is meant as a shortcut for $(SPHINXOPTS).\n%: Makefile\n\t@$(SPHINXBUILD) -M $@ \"$(SOURCEDIR)\" \"$(BUILDDIR)\" $(SPHINXOPTS) $(O)\n"
  },
  {
    "path": "doc/_static/.keep",
    "content": ""
  },
  {
    "path": "doc/_templates/layout.html",
    "content": "{% extends \"!layout.html\" %}\n\n{% block footer %}\n{{ super() }}\n    <script type=\"text/javascript\">\n(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){\n(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),\nm=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)\n})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');\n\nga('create', 'UA-45899190-2', 'auto');\nga('send', 'pageview');\n    </script>\n{% endblock %}\n"
  },
  {
    "path": "doc/about.rst",
    "content": "About\n=====\n\nCredits\n-------\n\nAn initial prototype was designed and enginered in one evening by Roman Tsisyk.\nAfter that the library was completely rewritten, tested and documented\n(which took a while).\n\nThe project exists only thanks to the excellent tracing just-in-time compiler\nin `LuaJIT <http://luajit.org>`_.\n\nThe library works best with `Tarantool <http://tarantool.org>`_ --\nan efficient in-memory database and Lua application server.\n\nCopying\n-------\n\nLua Fun source codes, logo and documentation are distributed under the\n`MIT License (MIT) <http://www.opensource.org/licenses/mit-license.php>`_ --\nsame as LuaJIT.\n\nCopyright (c) 2013-2017 Roman Tsisyk <roman@tsisyk.com>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "doc/basic.rst",
    "content": "Basic Functions\n===============\n\n.. currentmodule:: fun\n\nThe section contains functions to create iterators from Lua objects.\n\n.. function:: iter(array)\n              iter(map)\n              iter(string)\n              iter(gen, param, state)\n\n   :returns: ``gen, param, state`` -- :ref:`iterator triplet <iterator_triplet>`\n\n   Make ``gen, param, state`` iterator from the iterable object.\n   The function is a generalized version of :func:`pairs` and :func:`ipairs`.\n\n   The function distinguish between arrays and maps using ``#arg == 0``\n   check to detect maps. For arrays ``ipairs`` is used. For maps a modified\n   version of ``pairs`` is used that also returns keys. Userdata objects\n   are handled in the same way as tables.\n\n   If ``LUAJIT_ENABLE_LUA52COMPAT`` [#luajit_lua52compat]_ mode is enabled and\n   argument has metamethods ``__pairs`` (for maps) or ``__ipairs`` for (arrays),\n   call it with the table or userdata as argument and return the first three\n   results from the call [#lua52_ipairs]_.\n\n   All library iterator are suitable to use with Lua's ``for .. in`` loop.\n\n   .. code-block:: lua\n\n    > for _it, a in iter({1, 2, 3}) do print(a) end\n    1\n    2\n    3\n\n    > for _it, k, v in iter({ a = 1, b = 2, c = 3}) do print(k, v) end\n    b 2\n    a 1\n    c 3\n\n    > for _it, a in iter(\"abcde\") do print(a) end\n    a\n    b\n    c\n    d\n    e\n\n   The first cycle variable *_it* is needed to store an internal state of\n   the iterator. The value must be always ignored in loops:\n\n   .. code-block:: lua\n\n    for _it, a, b in iter({ a = 1, b = 2, c = 3}) do print(a, b) end\n    -- _it is some internal iterator state - always ignore it\n    -- a, b are values return from the iterator\n\n   Simple iterators like ``iter({1, 2, 3})`` have simple states, whereas\n   other iterators like :func:`zip` or :func:`chain` have complicated\n   internal states which values senseless for the end user.\n\n   Check out :doc:`under_the_hood` section for more details.\n\n   There is also the possibility to supply custom iterators to the\n   function:\n\n   .. code-block:: lua\n\n    > local function mypairs_gen(max, state)\n        if (state >= max) then\n                return nil\n        end\n        return state + 1, state + 1\n    end\n\n    > local function mypairs(max)\n        return mypairs_gen, max, 0\n    end\n\n    > for _it, a in iter(mypairs(10)) do print(a) end\n    1\n    2\n    3\n    4\n    5\n    6\n    7\n    8\n    9\n    10\n\n   Iterators can return multiple values.\n\n   Check out :doc:`under_the_hood` section for more details.\n\n   .. [#luajit_lua52compat] http://luajit.org/extensions.html\n   .. [#lua52_ipairs] http://www.lua.org/manual/5.2/manual.html#pdf-ipairs\n\n.. function:: each(fun, gen, param, state)\n              iterator:each(fun)\n\n   :returns: none\n\n   Execute the *fun* for each iteration value. The function is equivalent to\n   the code below:\n\n   .. code-block:: lua\n\n    for _it, ... in iter(gen, param, state) do\n        fun(...)\n    end\n\n   Examples:\n\n   .. code-block:: lua\n\n    > each(print, { a = 1, b = 2, c = 3})\n    b 2\n    a 1\n    c 3\n\n    > each(print, {1, 2, 3})\n    1\n    2\n    3\n\n   The function is used for its side effects. Implementation directly applies\n   *fun* to all iteration values without returning a new iterator, in contrast\n   to functions like :func:`map`.\n\n   .. seealso:: :func:`map`, :func:`reduce`\n\n.. function:: for_each(fun, gen, param, state)\n              iterator:for_each(fun)\n\n    An alias for :func:`each`.\n\n.. function:: foreach(fun, gen, param, state)\n              iterator:foreach(fun)\n\n    An alias for :func:`each`.\n"
  },
  {
    "path": "doc/compositions.rst",
    "content": "Compositions\n============\n\n.. currentmodule:: fun\n\n.. function:: zip(...)\n              iterator1:zip(iterator2, iterator3, ...)\n\n   :param ...: iterators to \"zip\"\n   :type  ...: iterator\n\n   :returns: an iterator\n\n   Return a new iterator where i-th return value contains the i-th element\n   from each of the iterators. The returned iterator is truncated in length\n   to the length of the shortest iterator. For multi-return iterators only the\n   first variable is used.\n\n   Examples:\n\n   .. code-block:: lua\n\n    > dump(zip({\"a\", \"b\", \"c\", \"d\"}, {\"one\", \"two\", \"three\"}))\n    a one\n    b two\n    c three\n\n    > each(print, zip())\n\n    > each(print, zip(range(5), {'a', 'b', 'c'}, rands()))\n    1       a       0.57514179487402\n    2       b       0.79693061238668\n    3       c       0.45174307459403\n\n    > each(print, zip(partition(function(x) return x > 7 end, range(1, 15, 1))))\n    8       1\n    9       2\n    10      3\n    11      4\n    12      5\n    13      6\n    14      7\n\n.. function:: cycle(gen, param, state)\n              iterator:cycle()\n\n   :returns: a cycled version of ``{gen, param, state}`` iterator\n\n   Make a new iterator that returns elements from ``{gen, param, state}``\n   iterator until the end and then \"restart\" iteration using a saved clone of\n   ``{gen, param, state}``. The returned iterator is constant space and no\n   return values are buffered. Instead of that the function make a clone of the\n   source ``{gen, param, state}`` iterator. Therefore, the source iterator\n   must be pure functional to make an identical clone. Infinity iterators\n   are supported, but are not recommended.\n\n   .. note:: ``{gen, param, state}`` must be pure functional to work properly\n            with the function.\n\n   Examples:\n\n   .. code-block:: lua\n\n    > each(print, take(15, cycle(range(5))))\n    1\n    2\n    3\n    4\n    5\n    1\n    2\n    3\n    4\n    5\n    1\n    2\n    3\n    4\n    5\n\n    > each(print, take(15, cycle(zip(range(5), {\"a\", \"b\", \"c\", \"d\", \"e\"}))))\n    1       a\n    2       b\n    3       c\n    4       d\n    5       e\n    1       a\n    2       b\n    3       c\n    4       d\n    5       e\n    1       a\n    2       b\n    3       c\n    4       d\n    5       e\n\n.. function:: chain(...)\n              iterator1:chain(iterator2, iterator3, ...)\n\n   :param ...: iterators to chain\n   :type  ...: iterator\n   :returns: a consecutive iterator from sources (left from right)\n\n   Make an iterator that returns elements from the first iterator until it is\n   exhausted, then proceeds to the next iterator, until all of the iterators\n   are exhausted. Used for treating consecutive iterators as a single iterator.\n   Infinity iterators are supported, but are not recommended.\n\n   Examples:\n\n   .. code-block:: lua\n\n    > each(print, chain(range(2), {\"a\", \"b\", \"c\"}, {\"one\", \"two\", \"three\"}))\n    1\n    2\n    a\n    b\n    c\n    one\n    two\n    three\n\n    > each(print, take(15, cycle(chain(enumerate({\"a\", \"b\", \"c\"}),\n        {\"one\", \"two\", \"three\"}))))\n    1       a\n    2       b\n    3       c\n    one\n    two\n    three\n    1       a\n    2       b\n    3       c\n    one\n    two\n    three\n    1       a\n    2       b\n    3       c\n"
  },
  {
    "path": "doc/conf.py",
    "content": "# Configuration file for the Sphinx documentation builder.\n#\n# This file only contains a selection of the most common options. For a full\n# list see the documentation:\n# https://www.sphinx-doc.org/en/master/usage/configuration.html\n\n# -- Path setup --------------------------------------------------------------\n\n# If extensions (or modules to document with autodoc) are in another directory,\n# add these directories to sys.path here. If the directory is relative to the\n# documentation root, use os.path.abspath to make it absolute, like shown here.\n#\n# import os\n# import sys\n# sys.path.insert(0, os.path.abspath('.'))\n\n\n# -- Project information -----------------------------------------------------\n\nproject = 'Lua Functional'\ncopyright = '2013-2021, Roman Tsisyk'\nauthor = 'Roman Tsisyk'\n\n# The short X.Y version\nversion = '0.1'\n\n# The full version, including alpha/beta/rc tags\nrelease = '0.1.3'\n\n\n# -- General configuration ---------------------------------------------------\n\n# Add any Sphinx extension module names here, as strings. They can be\n# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom\n# ones.\nextensions = [\n]\n\n# Add any paths that contain templates here, relative to this directory.\ntemplates_path = ['_templates']\n\n# The language for content autogenerated by Sphinx. Refer to documentation\n# for a list of supported languages.\n#\n# This is also used if you do content translation via gettext catalogs.\n# Usually you set \"language\" from the command line for these cases.\nlanguage = 'en'\n\n# List of patterns, relative to source directory, that match files and\n# directories to ignore when looking for source files.\n# This pattern also affects html_static_path and html_extra_path.\nexclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']\n\n\n# -- Options for HTML output -------------------------------------------------\n\n# The theme to use for HTML and HTML Help pages.  See the documentation for\n# a list of builtin themes.\n#\nhtml_theme = 'haiku'\n\n# Add any paths that contain custom static files (such as style sheets) here,\n# relative to this directory. They are copied after the builtin static files,\n# so a file named \"default.css\" will overwrite the builtin \"default.css\".\nhtml_static_path = ['_static']\n\n# The name of an image file (relative to this directory) to place at the top\n# of the sidebar.\nhtml_logo = 'logo.png'\n\n# If true, the reST sources are included in the HTML build as _sources/name.\n# The default is True.\nhtml_copy_source = False\n"
  },
  {
    "path": "doc/filtering.rst",
    "content": "Filtering\n=========\n\n.. currentmodule:: fun\n\nThis section contains functions to filter values during iteration.\n\n.. function:: filter(predicate, gen, param, state)\n              iterator:filter(predicate)\n\n   :param param: an predicate to filter the iterator\n   :type  param: (function(...) -> bool)\n\n   Return a new iterator of those elements that satisfy the **predicate**.\n\n   Examples:\n\n   .. code-block:: lua\n\n    > each(print, filter(function(x) return x % 3 == 0 end, range(10)))\n    3\n    6\n    9\n\n    > each(print, take(5, filter(function(i, x) return i % 3 == 0 end,\n        enumerate(duplicate('x')))))\n    3       x\n    6       x\n    9       x\n    12      x\n    15      x\n\n   .. note:: Multireturn iterators are supported but can cause performance \n             regressions.\n\n   .. seealso:: :func:`take_while` and :func:`drop_while`.\n\n.. function:: remove_if(predicate, gen, param, state)\n              iterator:remove_if(predicate)\n\n   An alias for :func:`filter`.\n\n.. function:: grep(regexp_or_predicate, gen, param, state)\n              iterator:grep(regexp_or_predicate)\n\n   If **regexp_or_predicate** is string then the parameter is used as a regular\n   expression to build filtering predicate. Otherwise the function is just an\n   alias for :func:`filter`.\n\n   Equivalent to:\n\n   .. code-block:: lua\n\n    local fun = regexp_or_predicate\n    if type(regexp_or_predicate) == \"string\" then\n        fun = function(x) return string.find(x, regexp_or_predicate) ~= nil end\n    end\n    return filter(fun, gen, param, state)\n\n   Examples:\n\n   .. code-block:: lua\n\n    lines_to_grep = {\n        [[Emily]],\n        [[Chloe]],\n        [[Megan]],\n        [[Jessica]],\n        [[Emma]],\n        [[Sarah]],\n        [[Elizabeth]],\n        [[Sophie]],\n        [[Olivia]],\n        [[Lauren]]\n    }\n\n    each(print, grep(\"^Em\", lines_to_grep))\n    --[[test\n    Emily\n    Emma\n    --test]]\n\n    each(print, grep(\"^P\", lines_to_grep))\n    --[[test\n    --test]]\n\n    > each(print, grep(function(x) return x % 3 == 0 end, range(10)))\n    3\n    6\n    9\n\n.. function:: partition(predicate, gen, param, state)\n              iterator:partition(predicate)\n\n   :param x: a value to find\n   :returns: {gen1, param1, state1}, {gen2, param2, state2}\n\n   The function returns two iterators where elements do and do not satisfy the\n   prediucate. Equivalent to:\n\n   .. code-block:: lua\n\n       return filter(predicate, gen', param', state'),\n       filter(function(...) return not predicate(...) end, gen, param, state);\n\n   The function make a clone of the source iterator. Iterators especially\n   returned in tables to work with :func:`zip` and other functions.\n\n   Examples:\n\n   .. code-block:: lua\n\n    > each(print, zip(partition(function(i, x) return i % 3 == 0 end, range(10))))\n    3       1\n    6       2\n    9       4\n\n   .. note:: ``gen, param, state`` must be pure functional to work properly\n             with the function.\n\n   .. seealso:: :func:`span`\n"
  },
  {
    "path": "doc/generators.rst",
    "content": "Generators\n==========\n\n.. currentmodule:: fun\n\nThis section contains a number of useful generators modeled after Standard ML,\nHaskell, Python, Ruby, JavaScript and other languages.\n\nFinite Generators\n-----------------\n\n.. function:: range([start,] stop[, step])\n\n   :param start: an endpoint of the interval (see below)\n   :type  start: number\n   :param stop: an endpoint of the interval (see below)\n   :type  stop: number\n   :param step: a step\n   :type  step: number\n\n   :returns: an iterator\n\n   The iterator to create arithmetic progressions. Iteration values are generated\n   within closed interval ``[start, stop]`` (i.e. *stop* is included).\n   If the *start* argument is omitted, it defaults to ``1`` (*stop* > 0) or\n   to ``-1`` (*stop* < 0). If the *step* argument is omitted, it defaults to\n   ``1`` (*start* <= *stop*) or to ``-1`` (*start* > *stop*).  If *step* is\n   positive, the last element is the largest ``start + i * step`` less than or\n   equal to *stop*; if *step* is negative, the last element is the smallest\n   ``start + i * step`` greater than or equal to *stop*.\n   *step* must not be zero (or else an error is raised).\n   ``range(0)`` returns empty iterator.\n\n   Examples:\n\n   .. code-block:: lua\n\n    > for _it, v in range(5) do print(v) end\n    1\n    2\n    3\n    4\n    5\n    > for _it, v in range(-5) do print(v) end\n    -1\n    -2\n    -3\n    -4\n    -5\n    > for _it, v in range(1, 6) do print(v) end\n    1\n    2\n    3\n    4\n    5\n    6\n    > for _it, v in range(0, 20, 5) do print(v) end\n    0\n    5\n    10\n    15\n    20\n    > for _it, v in range(0, 10, 3) do print(v) end\n    0\n    3\n    6\n    9\n    > for _it, v in range(0, 1.5, 0.2) do print(v) end\n    0\n    0.2\n    0.4\n    0.6\n    0.8\n    1\n    1.2\n    1.4\n    > for _it, v in range(0) do print(v) end\n    > for _it, v in range(1) do print(v) end\n    1\n    > for _it, v in range(1, 0) do print(v) end\n    1\n    0\n    > for _it, v in range(0, 10, 0) do print(v) end\n    error: step must not be zero\n\nInfinity Generators\n-------------------\n\n.. function:: duplicate(...)\n\n   :param ...: objects to duplicate\n   :type  ...: non nil\n   :returns: an iterator\n\n   The iterator returns values over and over again indefinitely. All values\n   that passed to the iterator are returned as-is during the iteration.\n\n   Examples:\n\n   .. code-block:: lua\n\n    > each(print, take(3, duplicate('a', 'b', 'c')))\n    a       b       c\n    a       b       c\n    > each(print, take(3, duplicate('x')))\n    x\n    x\n    x\n    > for _it, a, b, c, d, e in take(3, duplicate(1, 2, 'a', 3, 'b')) do\n        print(a, b, c, d, e)\n    >> end\n    1       2       a       3       b\n    1       2       a       3       b\n    1       2       a       3       b\n\n.. function:: xrepeat(...)\n\n   An alias for :func:`duplicate`.\n\n.. function:: replicate(...)\n\n   An alias for :func:`duplicate`.\n\n.. function:: tabulate(fun)\n\n   :param fun: an unary generating function\n   :type fun: function(n: uint) -> ... \n   :returns: an iterator\n\n   The iterator that returns ``fun(0)``, ``fun(1)``, ``fun(2)``, ``...`` values\n   indefinitely.\n\n   Examples:\n\n   .. code-block:: lua\n\n    > each(print, take(5, tabulate(function(x)  return 'a', 'b', 2*x end)))\n    a       b       0\n    a       b       2\n    a       b       4\n    a       b       6\n    a       b       8\n    > each(print, take(5, tabulate(function(x) return x^2 end)))\n    0\n    1\n    4\n    9\n    16\n\n.. function:: zeros()\n\n   :returns: an iterator\n\n   The iterator returns ``0`` indefinitely.\n\n   Examples:\n\n   .. code-block:: lua\n\n    > each(print, take(5, zeros()))\n    0\n    0\n    0\n    0\n    0\n\n.. function:: ones()\n\n   :returns: an iterator\n\n   The iterator that returns ``1`` indefinitely.\n\n   Example::\n\n    > each(print, take(5, ones()))\n    1\n    1\n    1\n    1\n    1\n\nRandom sampling\n---------------\n\n.. function:: rands([n[, m]])\n\n   :param n: an endpoint of the interval (see below)\n   :type  n: uint\n   :param m: an endpoint of the interval (see below)\n   :type  m: uint\n   :returns: an iterator\n\n   The iterator returns random values using :func:`math.random`.\n   If the **n** and **m** are set then the iterator returns pseudo-random\n   integers in the ``[n, m)`` interval (i.e. **m** is not included).\n   If the **m** is not set then the iterator generates pseudo-random integers\n   in the ``[0, n)`` interval. When called without arguments returns\n   pseudo-random real numbers with uniform distribution in the\n   interval ``[0, 1)``.\n\n   .. warning:: This iterator is not pure-functional and may not work as\n                expected with some library functions.\n\n   Examples:\n\n   .. code-block:: lua\n\n    > each(print, take(10, rands(10, 20)))\n    19\n    17\n    11\n    19\n    12\n    13\n    14\n    16\n    10\n    11\n\n    > each(print, take(5, rands(10)))\n    7\n    6\n    5\n    9\n    0\n\n    > each(print, take(5, rands()))\n    0.79420629243124\n    0.69885246563716\n    0.5901037417281\n    0.7532286166836\n    0.080971251199854\n\n"
  },
  {
    "path": "doc/getting_started.rst",
    "content": "Getting Started\n===============\n\nPlease jump to `Using the Library`_ section if you are familiar with Lua and\nLuaJIT.\n\n.. contents::\n\nPrerequisites\n-------------\n\nThe library is designed for LuaJIT_. **LuaJIT 2.1 alpha** is high^W **Highly**\nrecommended for performance reasons. Lua 5.1--5.3 are also supported.\n\nThe library is platform-independent and expected to work on all platforms that\nsupported by Lua(JIT). It can be also used in any Lua(JIT) based applications,\ne.g. Tarantool_ or OpenResty_.\n\nYou might need diff_ tool to run test system and sphinx_ to regenerate the\ndocumentation from source files.\n\n.. _LuaJIT: http://luajit.org/\n.. _Tarantool: http://tarantool.org/\n.. _OpenResty: http://openresty.org/\n.. _diff: http://en.wikipedia.org/wiki/Diff\n.. _sphinx: http://sphinx-doc.org/\n\nInstalling LuaJIT\n-----------------\n\nYou can build LuaJIT from sources or install it from a binary archive.\n\nFrom Sources\n````````````\n\n1. Clone LuaJIT git repository. Please note that **v2.1** branch is needed.\nYou can always select this branch using ``git checkout v2.1``.\n\n.. code-block:: bash\n\n    $ git clone http://luajit.org/git/luajit-2.0.git -b v2.1 luajit-2.1\n    Cloning into 'luajit-2.1'...\n\n2. Compile LuaJIT\n\n.. code-block:: bash\n\n    $ cd luajit-2.1/\n    luajit-2.1 $ make -j8\n\n3. Install LuaJIT\n\n.. code-block:: bash\n\n    luajit-2.1 $ make install\n    luajit-2.1 $ ln -s /usr/local/bin/luajit-2.1.0-alpha /usr/local/bin/luajit\n\nInstall operation might require root permissions. However, you can install\nLuaJIT into your home directory.\n\nFrom a Binary Archive\n`````````````````````\n\nIf operations above look too complicated for you, you always can download a\nbinary archive from http://luajit.org/download.html page.\nYour favorite package manager may also have LuaJIT packages.\n\nRunning LuaJIT\n``````````````\n\nEnsure that freshly installed LuaJIT works:\n\n.. code-block:: bash\n\n    $ luajit\n    LuaJIT 2.1.0-alpha -- Copyright (C) 2005-2013 Mike Pall. http://luajit.org/\n    JIT: ON SSE2 SSE3 SSE4.1 fold cse dce fwd dse narrow loop abc sink fuse\n    > = 2 + 2\n    4\n\nIt is good idea to use LuaJIT CLI under ``rlwrap`` (on nix platforms):\n\n.. code-block:: bash\n\n    alias luajit=\"rlwrap luajit\"\n    $ luajit\n    LuaJIT 2.1.0-alpha -- Copyright (C) 2005-2013 Mike Pall. http://luajit.org/\n    JIT: ON SSE2 SSE3 SSE4.1 fold cse dce fwd dse narrow loop abc sink fuse\n    > = 2 + 2\n    4\n    > = 2 + 2 <!-- You can use arrows, completion and so on, like in Bash\n\nInstalling the Library\n----------------------\n\nUsing LuaRocks\n``````````````\n\nUse the rockspec_ file.\n\n.. _rockspec: https://raw.github.com/luafun/luafun/master/fun-scm-1.rockspec\n\nUsing git\n`````````\n1. Clone Lua Fun repository:\n\n.. code-block:: bash\n\n    git clone git://github.com/luafun/luafun.git\n    $ cd luafun\n\n2. Run tests (optional):\n\n.. code-block:: bash\n\n    luafun $ cd tests\n    luafun/tests $ ./runtest *.lua\n    Testing basic.lua\n    Testing compositions.lua\n    Testing filters.lua\n    Testing folds.lua\n    Testing generators.lua\n    Testing slices.lua\n    Testing transformations.lua\n    All tests have passed!\n\nUsing wget\n``````````\n\nJust download https://raw.github.com/luafun/luafun/master/fun.lua file:\n\n.. code-block:: bash\n\n    $ wget https://raw.github.com/luafun/luafun/master/fun.lua\n\nUsing the Library\n-----------------\n\nTry to run LuaJIT in the same directory where ``fun.lua`` file is located:\n\n.. code-block:: bash\n   :emphasize-lines: 4\n\n    luafun $ luajit\n    LuaJIT 2.1.0-alpha -- Copyright (C) 2005-2013 Mike Pall. http://luajit.org/\n    JIT: ON SSE2 SSE3 fold cse dce fwd dse narrow loop abc sink fuse\n    > fun = require 'fun'\n    >\n    > for _k, a in fun.range(3) do print(a) end\n    1\n    2\n    3\n\nIf you see an error message like ``stdin:1: module 'fun' not found:`` then\nyou need to configure you Package Path (``package.path``). Please consult\n`Lua Wiki <http://lua-users.org/wiki/PackagePath>`_ for additional information.\n\n\n**Lua Fun** designed to be small ubiquitous library. It is a good idea to import\nall library functions to the global table:\n\n.. code-block:: bash\n   :emphasize-lines: 1\n\n    > for k, v in pairs(require \"fun\") do _G[k] = v end -- import fun.*\n    > for _k, a in range(3) do print(a) end\n    0\n    1\n    2\n\n**Lua Fun** also provides a special **shortcut** to autoimport all functions:\n\n.. code-block:: bash\n   :emphasize-lines: 1\n\n    > require 'fun'() -- to import all lua.* functions to globals\n    > each(print, range(5))\n    1\n    2\n    3\n    4\n    5\n\nNow you can use **Lua Fun**:\n\n.. code-block:: bash\n\n    > print(sum(filter(function(x) return x % 16 == 0 end, range(10000))))\n    3130000\n\n    > each(print, take(5, tabulate(math.sin)))\n    0\n    2\n    4\n    6\n    8\n\n    > each(print, enumerate(zip({\"one\", \"two\", \"three\", \"four\", \"five\"},\n        {\"a\", \"b\", \"c\", \"d\", \"e\"})))\n    1       one     a\n    2       two     b\n    3       three   c\n    4       four    d\n    5       five    e\n\n    > lines_to_grep = {\n        [[Emily]],\n        [[Chloe]],\n        [[Megan]],\n        [[Jessica]],\n        [[Emma]],\n        [[Sarah]],\n        [[Elizabeth]],\n        [[Sophie]],\n        [[Olivia]],\n        [[Lauren]]\n    }\n\n    > each(print, grep(\"Em\", lines_to_grep))\n    Emily\n    Emma\n\n    > each(print, take(10, cycle(chain(\n        {enumerate({\"a\", \"b\", \"c\"})},\n        {\"one\", \"two\", \"three\"}))\n      ))\n    0 a\n    1 b\n    2 c\n    one\n    two\n    three\n    0 a\n    1 b\n    2 c\n    one\n\nPlease note that functions support multireturn.\n\nFurther Actions\n---------------\n\n- Take a look on :doc:`reference`.\n- Use :ref:`genindex` to find functions by its names.\n- Checkout **examples** from\n  `tests/ <https://github.com/luafun/luafun/tree/master/tests>`_ directory\n- Read :doc:`under_the_hood` section\n- \"Star\" us the on GitHub_ to help the project to survive\n- Make Great Software\n- Have fun\n\n**Lua Fun**. Simple, Efficient and Functional. In Lua. With JIT.\n\n.. _GitHub: http://github.com/luafun/luafun\n"
  },
  {
    "path": "doc/index.rst",
    "content": ".. _library-index:\n\n###############################\n  Lua Functional Library\n###############################\n\n:Release: |version|\n:Date: |today|\n\n.. highlight:: lua\n\nContents\n========\n\n.. toctree::\n   :maxdepth: 2\n\n   intro.rst\n   getting_started.rst\n   reference.rst\n   under_the_hood.rst\n   about.rst\n\nIndices and tables\n==================\n\n* :ref:`genindex`\n* :ref:`search`\n\n"
  },
  {
    "path": "doc/indexing.rst",
    "content": "Indexing\n========\n\n.. currentmodule:: fun\n\nThis section contains functions to find elements by its values.\n\n.. function:: index(x, gen, param, state)\n              iterator:index(x)\n\n   :param x: a value to find\n   :returns: the position of the first element that equals to the **x**\n\n   The function returns the position of the first element in the given iterator\n   which is equal (using ``==``) to the query element, or ``nil`` if there is\n   no such element.\n\n   Examples:\n\n   .. code-block:: lua\n\n    > print(index(2, range(0)))\n    nil\n\n    > print(index(\"b\", {\"a\", \"b\", \"c\", \"d\", \"e\"}))\n    2\n\n.. function:: index_of(x, gen, param, state)\n              iterator:index_of(x)\n\n   An alias for :func:`index`.\n\n.. function:: elem_index(x, gen, param, state)\n              iterator:elem_index(x)\n\n   An alias for :func:`index`.\n\n.. function:: indexes(x, gen, param, state)\n              iterator:indexes(x)\n\n   :param x: a value to find\n   :returns: an iterator which positions of elements that equal to the **x**\n\n   The function returns an iterator to positions of elements which equals to \n   the query element.\n\n   Examples:\n\n   .. code-block:: lua\n\n    > each(print, indexes(\"a\", {\"a\", \"b\", \"c\", \"d\", \"e\", \"a\", \"b\", \"a\", \"a\"}))\n    1\n    6\n    9\n    10\n\n   .. seealso:: :func:`filter`\n\n.. function:: indices(x, gen, param, state)\n              iterator:indices(x)\n\n   An alias for :func:`indexes`.\n\n.. function:: elem_indexes(x, gen, param, state)\n              iterator:elem_indexes(x)\n\n   An alias for :func:`indexes`.\n\n.. function:: elem_indices(x, gen, param, state)\n              iterator:elem_indices(x)\n\n   An alias for :func:`indexes`.\n\n\n"
  },
  {
    "path": "doc/intro.rst",
    "content": "Introduction\n============\n\n.. currentmodule:: fun\n\n**Lua Fun** is a high-performance functional programming library\ndesigned for `LuaJIT tracing just-in-time compiler\n<http://luajit.org/luajit.html>`_.\n\nThe library provides a set of more than 50 programming primitives typically\nfound in languages like Standard ML, Haskell, Erlang, JavaScript, Python and\neven Lisp. High-order functions such as :func:`map`, :func:`filter`,\n:func:`reduce`, :func:`zip` will help you to **write simple and efficient\nfunctional code**.\n\nLet's see an example:\n\n.. code-block:: lua\n   :emphasize-lines: 2, 4\n\n    -- Functional style\n    require \"fun\" ()\n    n = 100\n    x = sum(map(function(x) return x^2 end, take(n, tabulate(math.sin))))\n    -- calculate sum(sin(x)^2 for x in 0..n-1)\n    print(x)\n    50.011981355266\n\n.. code-block:: lua\n   :emphasize-lines: 2, 4\n\n    -- Object-oriented style\n    local fun = require \"fun\"\n    n = 100\n    x = fun.tabulate(math.sin):take(n):map(function(x) return x^2 end):sum()\n    -- calculate sum(sin(x)^2 for x in 0..n-1)\n    print(x)\n    50.011981355266\n\n**Lua Fun** takes full advantage of the innovative **tracing JIT compiler**\nto achieve transcendental performance on nested functional expressions.\nFunctional compositions and high-order functions can be translated into\n**efficient machine code**. Can you believe it? Just try to run the example above\nwith ``luajit -jdump`` and see what happens:\n\n.. code-block:: none\n   :emphasize-lines: 2,14\n\n    -- skip some initialization code --\n    ->LOOP:\n    0bcaffd0  movsd [rsp+0x8], xmm7\n    0bcaffd6  addsd xmm4, xmm5\n    0bcaffda  ucomisd xmm6, xmm1\n    0bcaffde  jnb 0x0bca0028        ->6\n    0bcaffe4  addsd xmm6, xmm0\n    0bcaffe8  addsd xmm7, xmm0\n    0bcaffec  fld qword [rsp+0x8]\n    0bcafff0  fsin\n    0bcafff2  fstp qword [rsp]\n    0bcafff5  movsd xmm5, [rsp]\n    0bcafffa  mulsd xmm5, xmm5\n    0bcafffe  jmp 0x0bcaffd0        ->LOOP\n    ---- TRACE 1 stop -> loop\n\n\nThe functional chain above was translated by LuaJIT to (!) **one machine loop**\ncontaining just 10 CPU assembly instructions without CALL. Unbelievable!\n\nReadable? Efficient? Can your Python/Ruby/V8 do better?\n"
  },
  {
    "path": "doc/operators.rst",
    "content": "Operators\n=========\n\n.. module:: fun.operator\n\nThis auxiliary module exports a set of Lua operators as intrinsic functions\nto use with the library high-order primitives.\n\n.. contents::\n\n.. note:: **op** can be used as a shortcut to **operator**.\n\nComparison operators\n--------------------\n\n.. seealso:: `Lua Relational Operators\n              <http://www.lua.org/manual/5.2/manual.html#3.4.3>`_\n\n.. function:: le(a, b)\n\n   :returns: **a** <= **b**\n\n.. function:: lt(a, b)\n\n   :returns: **a** < **b**\n\n.. function:: eq(a, b)\n\n   :returns: **a** == **b**\n\n.. function:: ne(a, b)\n\n   :returns: **a** ~= **b**\n\n.. function:: ge(a, b)\n\n   :returns: **a** >= **b**\n\n.. function:: gt(a, b)\n\n   :returns: **a** > **b**\n\nArithmetic operators\n--------------------\n\n.. seealso:: `Lua Arithmetic Operators \n              <http://www.lua.org/manual/5.2/manual.html#3.4.1>`_\n\n.. function:: add(a, b)\n\n   :returns: **a** + **b**\n\n.. function:: div(a, b)\n\n    An alias for :func:`truediv`.\n\n.. function:: truediv(a, b)\n\n   :returns: **a** / **b**\n\n   Performs \"true\" float division.\n   Examples:\n\n   .. code-block:: lua\n\n    > print(operator.div(10, 3))\n    3.3333333333333\n    > print(operator.div(-10, 3))\n    -3.3333333333333\n\n.. function:: floordiv(a, b)\n\n   :returns: math.floor(**a** / **b**)\n\n   Performs division where a result is rounded down. Examples:\n\n   .. code-block:: lua\n\n    > print(operator.floordiv(10, 3))\n    3\n    > print(operator.floordiv(12, 3))\n    4\n    > print(operator.floordiv(-10, 3))\n    -4\n    > print(operator.floordiv(-12, 3))\n    -4\n\n.. function:: intdiv(a, b)\n\n   Performs C-like integer division.\n\n   Equivalent to:\n\n   .. code-block:: lua\n\n    function(a, b)\n        local q = a / b\n        if a >= 0 then return math.floor(q) else return math.ceil(q) end\n    end\n\n   Examples:\n\n   .. code-block:: lua\n\n    > print(operator.floordiv(10, 3))\n    3\n    > print(operator.floordiv(12, 3))\n    4\n    > print(operator.floordiv(-10, 3))\n    -3\n    > print(operator.floordiv(-12, 3))\n    -4\n\n.. function:: mod(a, b)\n\n   :returns: **a** % **b**\n\n   .. note:: Result has same sign as **divisor**. Modulo in Lua is defined as\n             ``a % b == a - math.floor(a/b)*b``.\n\n   Examples:\n\n   .. code-block:: lua\n    :emphasize-lines: 5-6\n\n    > print(operator.mod(10, 2))\n    0\n    > print(operator.mod(10, 3))\n    2\n    print(operator.mod(-10, 3))\n    2 -- == -1 in C, Java, JavaScript and but not in Lua, Python, Haskell!\n\n.. function:: neq(a)\n\n   :returns: -**a**\n\n.. function:: unm(a)\n\n   Unary minus. An alias for :func:`neq`.\n\n.. function:: pow(a, b)\n\n   :returns: math.pow(**a**, **b**)\n\n.. function:: sub(a, b)\n\n   :returns: **a** - **b**\n\nString operators\n----------------\n\n.. seealso:: `Lua Concatenation Operator\n              <http://www.lua.org/manual/5.2/manual.html#3.4.5>`_\n\n.. function:: concat(a, b)\n\n   :returns: **a** .. **b**\n\n.. function:: len(a)\n\n   :returns: # **a**\n\n.. function:: length(a)\n\n   An alias for :func:`len`.\n\nLogical operators\n-----------------\n\n.. seealso:: `Lua Logical Operators\n              <http://www.lua.org/manual/5.2/manual.html#3.4.4>`_\n\n.. function:: land(a, b)\n\n   :returns: **a** and **b**\n\n.. function:: lor(a, b)\n\n   :returns: **a** or **b**\n\n.. function:: lnot(a)\n\n   :returns: not **a**\n\n.. function:: truth(a)\n\n   :returns: not not **a**\n\n   Return ``true`` if **a** is true, and ``false`` otherwise. Examples:\n\n   .. code-block:: lua\n\n    > print(operator.truth(1))\n    true\n    > print(operator.truth(0))\n    true -- It is Lua, baby!\n    > print(operator.truth(nil))\n    false\n    > print(operator.truth(\"\"))\n    true\n    > print(operator.truth({}))\n    true\n\n"
  },
  {
    "path": "doc/reducing.rst",
    "content": "Reducing\n========\n\n.. currentmodule:: fun\n\nThe section contains functions to analyze iteration values and recombine\nthrough use of a given combining operation the results of recursively processing\nits constituent parts, building up a return value\n\n.. contents::\n\n.. note:: An attempt to use infinity iterators with the most function from\n          the module causes an infinite loop.\n\nFolds\n-----\n\n.. function:: foldl(accfun, initval, gen, param, state)\n              iterator:reduce(accfun, initval)\n\n   :param accfun: an accumulating function\n   :type  param: (function(prevval, ...) -> val)\n   :param initval: an initial value that passed to **accfun** on the first\n          iteration\n\n   The function reduces the iterator from left to right using the binary\n   operator **accfun** and the initial value **initval**.\n   Equivalent to::\n\n        local val = initval\n        for _k, ... in gen, param, state do\n            val = accfun(val, ...)\n        end\n        return val\n\n   Examples:\n\n   .. code-block:: lua\n\n    > print(foldl(function(acc, x) return acc + x end, 0, range(5)))\n    15\n\n    > print(foldl(operator.add, 0, range(5)))\n    15\n\n    > print(foldl(function(acc, x, y) return acc + x * y; end, 0,\n        zip(range(1, 5), {4, 3, 2, 1})))\n    20\n\n.. function:: reduce(accfun, initval, gen, param, state)\n              iterator:reduce(accfun, initval)\n\n   An alias to :func:`foldl`.\n\n.. function:: length(gen, param, state)\n              iterator:length()\n\n   Return a number of remaining elements in ``gen, param, state`` iterator.\n\n   Examples:\n\n   .. code-block:: lua\n\n    > print(length({\"a\", \"b\", \"c\", \"d\", \"e\"}))\n    5\n\n    > print(length(drop_n(3, {\"a\", \"b\", \"c\", \"d\", \"e\"})))\n    2\n\n    > print(length({}))\n    0\n\n    > print(length(range(0)))\n    0\n\n   .. warning:: An attempt to call this function on an infinite iterator will\n                result an infinite loop.\n\n   .. note:: This function has ``O(n)`` complexity for all iterators except\n             basic array and string iterators, where it has ``O(1)`` complexity.\n\n.. function:: totable(gen, param, state)\n\n   :returns: a new table (array) from iterated values.\n\n   The function reduces the iterator from left to right using ``table.insert``.\n\n   Examples:\n\n   .. code-block:: lua\n\n    > local tab = totable(\"abcdef\")\n    > print(type(tab), #tab)\n    table 6\n    > each(print, tab)\n    a\n    b\n    c\n    d\n    e\n    f\n\n.. function:: tomap(gen, param, state)\n\n   :returns: a new table (map) from iterated values.\n\n   The function reduces the iterator from left to right using\n   ``tab[val1] = val2`` expression.\n\n   Examples:\n\n   .. code-block:: lua\n\n    > local tab = tomap(zip(range(1, 7), 'abcdef'))\n    > print(type(tab), #tab)\n    table   6\n    > each(print, iter(tab))\n    a\n    b\n    c\n    d\n    e\n    f\n\nPredicates\n----------\n\n.. function:: is_prefix_of(iterator1, iterator2)\n              iterator1:is_prefix_of(iterator2)\n\n   The function takes two iterators and returns ``true`` if the first iterator\n   is a prefix of the second. \n\n   Examples:\n\n   .. code-block:: lua\n\n    > print(is_prefix_of({\"a\"}, {\"a\", \"b\", \"c\"}))\n    true\n\n    > print(is_prefix_of(range(6), range(5)))\n    false\n\n.. function:: is_null(gen, param, state)\n              iterator:is_null()\n\n   :returns: true when `gen, param, state`` iterator is empty or finished.\n   :returns: false otherwise.\n\n   Example::\n\n    > print(is_null({\"a\", \"b\", \"c\", \"d\", \"e\"}))\n    false\n\n    > print(is_null({}))\n    true\n\n    > print(is_null(range(0)))\n    true\n\n.. function:: all(predicate, gen, param, state)\n              iterator:all(predicate)\n\n   :param predicate: a predicate\n\n   Returns true if all return values of iterator satisfy the **predicate**.\n\n   Examples:\n\n   .. code-block:: lua\n\n    > print(all(function(x) return x end, {true, true, true, true}))\n    true\n\n    > print(all(function(x) return x end, {true, true, true, false}))\n    false\n\n.. function:: every(predicate, gen, param, state)\n\n   An alias for :func:`all`.\n\n.. function:: any(predicate, gen, param, state)\n              iterator:any(predicate)\n\n   :param predicate: a predicate\n\n   Returns ``true`` if at least one return values of iterator satisfy the\n   **predicate**. The iteration stops on the first such value. Therefore,\n   infinity iterators that have at least one satisfying value might work.\n\n   Examples:\n\n   .. code-block:: lua\n\n    > print(any(function(x) return x end, {false, false, false, false}))\n    false\n\n    > print(any(function(x) return x end, {false, false, false, true}))\n    true\n\n.. function:: some(predicate, gen, param, state)\n\n   An alias for :func:`any`.\n\nSpecial folds\n-------------\n\n.. function:: sum(gen, param, state)\n              iterator:sum()\n\n   Sum up all iteration values. An optimized alias for::\n\n       foldl(operator.add, 0, gen, param, state)\n\n   For an empty iterator ``0`` is returned.\n\n   Examples:\n\n   .. code-block:: lua\n\n    > print(sum(range(5)))\n    15\n\n.. function:: product(gen, param, state)\n              iterator:product()\n\n   Multiply all iteration values. An optimized alias for::\n\n       foldl(operator.mul, 1, gen, param, state)\n\n   For an empty iterator ``1`` is returned.\n\n   Examples:\n\n   .. code-block:: lua\n\n    > print(product(range(1, 5)))\n    120\n\n.. function:: min(gen, param, state)\n              iterator:min()\n\n   Return a minimum value from the iterator using :func:`operator.min` or ``<``\n   for numbers and other types respectively. The iterator must be\n   non-null, otherwise an error is raised.\n\n   Examples:\n\n   .. code-block:: lua\n\n    > print(min(range(1, 10, 1)))\n    1\n\n    > print(min({\"f\", \"d\", \"c\", \"d\", \"e\"}))\n    c\n\n    > print(min({}))\n    error: min: iterator is empty\n\n.. function:: minimum(gen, param, state)\n\n   An alias for :func:`min`.\n\n.. function:: min_by(cmp, gen, param, state)\n              iterator:min_by(cmp)\n\n   Return a minimum value from the iterator using the **cmp** as a ``<``\n   operator. The iterator must be non-null, otherwise an error is raised.\n\n   Examples:\n\n   .. code-block:: lua\n\n    > function min_cmp(a, b) if -a < -b then return a else return b end end\n    > print(min_by(min_cmp, range(1, 10, 1)))\n    9\n\n.. function:: minimum_by(cmp, gen, param, state)\n\n   An alias for :func:`min_by`.\n\n.. function:: max(gen, param, state)\n              iterator:max()\n\n   Return a maximum value from the iterator using :func:`operator.max` or ``>``\n   for numbers and other types respectively.\n\n   The iterator must be non-null, otherwise an error is raised.\n\n   Examples:\n\n   .. code-block:: lua\n\n    > print(max(range(1, 10, 1)))\n    9\n\n    > print(max({\"f\", \"d\", \"c\", \"d\", \"e\"}))\n    f\n\n    > print(max({}))\n    error: max: iterator is empty\n\n.. function:: maximum(gen, param, state)\n\n   An alias for :func:`max`.\n\n.. function:: max_by(cmp, gen, param, state)\n              iterator:max_by(cmp)\n\n   Return a maximum value from the iterator using the **cmp** as a `>`\n   operator. The iterator must be non-null, otherwise an error is raised.\n\n   Examples:\n\n   .. code-block:: lua\n\n    > function max_cmp(a, b) if -a > -b then return a else return b end end\n    > print(max_by(max_cmp, range(1, 10, 1)))\n    1\n\n.. function:: maximum_by(cmp, gen, param, state)\n\n   An alias for :func:`max_by`.\n"
  },
  {
    "path": "doc/reference.rst",
    "content": "API Reference\n=============\n\n.. module:: fun\n\n.. toctree::\n\n   basic.rst\n   generators.rst\n   slicing.rst\n   indexing.rst\n   filtering.rst\n   reducing.rst\n   transformations.rst\n   compositions.rst\n   operators.rst\n"
  },
  {
    "path": "doc/slicing.rst",
    "content": "Slicing\n=======\n\n.. currentmodule:: fun\n\nThis section contains functions to make subsequences from iterators.\n\nBasic\n-----\n\n.. function:: nth(n, gen, param, state)\n              iterator:nth(n)\n\n   :param uint n: a sequential number (indexed starting from ``1``,\n                  like Lua tables)\n   :returns: **n**-th element of ``gen, param, state`` iterator\n\n   This function returns the **n**-th element of ``gen, param, state``\n   iterator. If the iterator does not have **n** items then ``nil`` is returned.\n\n   Examples:\n\n   .. code-block:: lua\n\n    > print(nth(2, range(5)))\n    2\n\n    > print(nth(10, range(5)))\n    nil\n\n    > print(nth(2, {\"a\", \"b\", \"c\", \"d\", \"e\"}))\n    b\n\n    > print(nth(2, drop_n(3, {\"a\", \"b\", \"c\", \"d\", \"e\"})))\n    e\n\n    > print(nth(2, enumerate({\"a\", \"b\", \"c\", \"d\", \"e\"})))\n    2 b\n\n   This function is optimized for basic array and string iterators and has\n   ``O(1)`` complexity for these cases.\n\n.. function:: head(gen, param, state)\n              iterator:head()\n\n   :returns: a first element of ``gen, param, state`` iterator\n\n   Extract the first element of ``gen, param, state`` iterator.\n   If the iterator is empty then an error is raised.\n\n   Examples:\n\n   .. code-block:: lua\n\n    > print(head({\"a\", \"b\", \"c\", \"d\", \"e\"}))\n    a\n    > print(head({}))\n    error: head: iterator is empty\n    > print(head(range(0)))\n    error: head: iterator is empty\n    > print(head(enumerate({\"a\", \"b\"})))\n    1 a\n\n.. function:: car(gen, param, state)\n\n   An alias for :func:`head`.\n\n.. function:: tail(gen, param, state)\n              iterator:tail()\n\n   :returns: ``gen, param, state`` iterator without a first element\n\n   Return a copy of ``gen, param, state`` iterator without its first element.\n   If the iterator is empty then an empty iterator is returned.\n\n   Examples:\n\n   .. code-block:: lua\n\n    > each(print, tail({\"a\", \"b\", \"c\", \"d\", \"e\"}))\n    b\n    c\n    d\n    e\n    > each(print, tail({}))\n    > each(print, tail(range(0)))\n    > each(print, tail(enumerate({\"a\", \"b\", \"c\"})))\n    2 b\n    3 c\n\n.. function:: cdr(gen, param, state)\n\n   An alias for :func:`tail`.\n\nSubsequences\n------------\n\n.. function:: take_n(n, gen, param, state)\n              iterator:take_n(n)\n\n   :param n: a number of elements to take\n   :type  n: uint\n   :returns: an iterator on the subsequence of first **n** elements\n\n   Examples:\n\n   .. code-block:: lua\n\n    > each(print, take_n(5, range(10)))\n    1\n    2\n    3\n    4\n    5\n\n    > each(print, take_n(5, enumerate(duplicate('x'))))\n    1 x\n    2 x\n    3 x\n    4 x\n    5 x\n\n.. function:: take_while(predicate, gen, param, state)\n              iterator:take_while(predicate)\n\n   :type predicate: function(...) -> bool\n   :returns: an iterator on the longest prefix of ``gen, param, state``\n             elements that satisfy **predicate**.\n\n   Examples:\n\n   .. code-block:: lua\n\n    > each(print, take_while(function(x) return x < 5 end, range(10)))\n    1\n    2\n    3\n    4\n\n    > each(print, take_while(function(i, a) return i ~=a end,\n        enumerate({5, 3, 4, 4, 2})))\n    1       5\n    2       3\n    3       4\n\n   .. seealso:: :func:`filter`\n\n.. function:: take(n_or_predicate, gen, param, state)\n              iterator:take(n_or_predicate)\n\n   An alias for :func:`take_n` and :func:`take_while` that autodetects\n   required function based on **n_or_predicate** type.\n\n.. function:: drop_n(n, gen, param, state)\n              iterator:drop_n(n)\n\n   :param n: the number of elements to drop\n   :type  n: uint\n   :returns: ``gen, param, state`` iterator after skipping first **n**\n             elements\n\n   Examples:\n\n   .. code-block:: lua\n\n    > each(print, drop_n(2, range(5)))\n    3\n    4\n    5\n\n    > each(print, drop_n(2, enumerate({'a', 'b', 'c', 'd', 'e'})))\n    3       c\n    4       d\n    5       e\n\n.. function:: drop_while(predicate, gen, param, state)\n              iterator:drop_while(predicate)\n\n   :type predicate: function(...) -> bool\n   :returns: ``gen, param, state`` after skipping the longest prefix\n             of  elements that satisfy **predicate**.\n\n   Examples:\n\n   .. code-block:: lua\n\n    > each(print, drop_while(function(x) return x < 5 end, range(10)))\n    5\n    6\n    7\n    8\n    9\n    10\n\n   .. seealso:: :func:`filter`\n\n.. function:: drop(n_or_predicate, gen, param, state)\n              iterator:drop(n_or_predicate)\n\n   An alias for :func:`drop_n` and :func:`drop_while` that autodetects\n   required function based on **n_or_predicate** type.\n\n\n.. function:: span(n_or_predicate, gen, param, state)\n              iterator:span(n_or_predicate)\n\n   :type n_or_predicate: function(...) -> bool or uint\n   :returns: iterator, iterator\n\n   Return an iterator pair where the first operates on the longest prefix\n   (possibly empty) of ``gen, param, state`` iterator of elements that\n   satisfy **predicate** and second operates the remainder of\n   ``gen, param, state`` iterator. \n   Equivalent to:\n\n   .. code-block:: lua\n\n       return take(n_or_predicate, gen, param, state),\n              drop(n_or_predicate, gen, param, state);\n\n   Examples:\n\n   .. code-block:: lua\n\n    > each(print, zip(span(function(x) return x < 5 end, range(10))))\n    1       5\n    2       6\n    3       7\n    4       8\n\n    > each(print, zip(span(5, range(10))))\n    1       6\n    2       7\n    3       8\n    4       9\n    5       10\n\n   .. note:: ``gen, param, state`` must be pure functional to work properly\n             with the function.\n\n   .. seealso:: :func:`partition`\n\n.. function:: split(n_or_predicate, gen, param, state)\n\n    An alias for :func:`span`.\n\n.. function:: split_at(n, gen, param, state)\n\n    An alias for :func:`span`.\n"
  },
  {
    "path": "doc/transformations.rst",
    "content": "Transformations\n===============\n\n.. currentmodule:: fun\n\n.. function:: map(fun, gen, param, state)\n              iterator:map(fun)\n\n   :param fun: a function to apply\n   :type  fun: (function(...) -> ...)\n   :returns: a new iterator\n\n   Return a new iterator by applying the **fun** to each element of\n   ``gen, param, state`` iterator. The mapping is performed on the fly\n   and no values are buffered.\n\n   Examples:\n\n   .. code-block:: lua\n\n    > each(print, map(function(x) return 2 * x end, range(4)))\n    2\n    4\n    6\n    8\n\n    fun = function(...) return 'map', ... end\n    > each(print, map(fun, range(4)))\n    map 1\n    map 2\n    map 3\n    map 4\n\n.. function:: enumerate(gen, param, state)\n              iterator:enumerate()\n\n   :returns: a new iterator\n\n   Return a new iterator by enumerating all elements of the\n   ``gen, param, state`` iterator starting from ``1``. The mapping is performed\n   on the fly and no values are buffered.\n\n   Examples:\n\n   .. code-block:: lua\n\n    > each(print, enumerate({\"a\", \"b\", \"c\", \"d\", \"e\"}))\n    1 a\n    2 b\n    3 c\n    4 d\n    5 e\n\n    > each(print, enumerate(zip({\"one\", \"two\", \"three\", \"four\", \"five\"},\n        {\"a\", \"b\", \"c\", \"d\", \"e\"})))\n    1 one a\n    2 two b\n    3 three c\n    4 four d\n    5 five e\n\n.. function:: intersperse(x, gen, param, state)\n              iterator:intersperse(x)\n\n   :type x: any\n   :returns: a new iterator\n\n   Return a new iterator where the **x** value is interspersed between the\n   elements of the source iterator. The **x** value can also be added as a\n   last element of returning iterator if the source iterator contains the odd\n   number of elements.\n\n   Examples:\n\n   .. code-block:: lua\n\n    > each(print, intersperse(\"x\", {\"a\", \"b\", \"c\", \"d\", \"e\"}))\n    a\n    x\n    b\n    x\n    c\n    x\n    d\n    x\n    e\n    x\n"
  },
  {
    "path": "doc/under_the_hood.rst",
    "content": "Under the Hood\n==============\n\n.. currentmodule:: fun\n\nThe section sheds some light on the internal library structure and working\nprinciples.\n\nIterators\n---------\n\nAnother basic primitive of the library (after functions) is the iterator. Most functions\ntake an iterator and return a new iterator or several ones. Iterators all the way down!\n[#iterators]_.\n\nThe simplest iterators are (surprise!) the :func:`pairs` and :func:`ipairs`\nLua functions. Have you ever tried calling, say, the :func:`ipairs` function\nwithout using it inside a ``for`` loop? Try to do that on any Lua\nimplementation:\n\n.. _iterator_triplet:\n.. code-block:: bash\n\n    > =ipairs({'a', 'b', 'c'})\n    function: builtin#6     table: 0x40f80e38       0\n\nThe function returned three strange values which look useless without a ``for``\nloop. We call these values an **iterator triplet**.\nLet's see what each value is used for:\n\n``gen`` -- first value\n   A generating function that can produce a next value on each iteration.\n   Usually returns a new ``state`` and iteration values (multireturn).\n\n``param`` -- second value\n   A permanent (constant) parameter of the generating function. It is used to create\n   a specific instance of the generating function. For example, the table itself\n   in the ``ipairs`` case.\n\n``state`` -- third value\n   A some transient state of an iterator that is changed after each iteration.\n   For example, the array index in the ``ipairs`` case.\n\nTry calling the ``gen`` function manually:\n\n   .. code-block:: lua\n\n    > gen, param, state = ipairs({'a', 'b', 'c'})\n    > =gen(param, state)\n    1       a\n\nThe ``gen`` function returned a new state ``1`` and the next iteration\nvalue ``a``. The second call to ``gen`` with the new state will return the next\nstate and the next iteration value. When the iterator gets to the end\nthe ``nil`` value is returned instead of the next state.\n\n**Please do not panic!** You do not have to use these values directly.\nIt is just a nice trick to get ``for .. in`` loops working in Lua.\n\nIterations\n----------\n\nWhat happens when you type the following code into a Lua console::\n\n    for _it, x in ipairs({'a', 'b', 'c'}) do print(x) end\n\nAccording to Lua reference manual [#lua_for]_ the code above is equivalent to::\n\n    do\n        -- Initialize the iterator\n        local gen, param, state = ipairs({'a', 'b', 'c'})\n        while true do\n            -- Next iteration\n            local state, var_1, ···, var_n = gen(param, state)\n            if state == nil then break end\n            -- Assign values to our variables\n            _it = state\n            x = var_1\n            -- Execute the code block\n            print(x)\n        end\n    end\n\nWhat does it mean for us?\n\n* An iterator can be used together with ``for .. in`` to generate a loop\n* An iterator is fully defined by the ``gen``, ``param`` and ``state`` iterator\n  triplet\n* The ``nil`` state marks the end of an iteration\n* An iterator can return an arbitrary number of values (multireturn)\n* It is possible to make some wrapping functions to take an iterator and\n  return a new modified iterator\n\n**The library provides a set of iterators** that can be used like ``pairs``\nand ``ipairs``.\n\nIterator Types\n--------------\n\nPure functional iterators\n`````````````````````````\n\nIterators can be either purely functional or have some side effects and return\ndifferent values for the same initial conditions [#pure_function]_. An **iterator is\npurely functional** if it meets the following criteria:\n\n- ``gen`` function always returns the same values for the same ``param`` and\n  ``state`` values (idempotence property)\n- ``param`` and ``state`` values are not modified during the ``gen`` call and\n  a new ``state`` object is returned instead (referential transparency\n  property).\n\nPure functional iterators are very important for us. Pure functional iterator\ncan be safety cloned or reapplied without creating side effects. Many library\nfunction use these properties.\n\nFinite iterators\n````````````````\n\nIterators can be **finite** (sooner or later end up) or **infinite**\n(never end).\nSince there is no way to determine automatically if an iterator is finite or\nnot [#turing]_ the library function can not automatically resolve infinite\nloops. It is your obligation not to pass infinite iterators to reducing\nfunctions.\n\nTracing JIT\n-----------\n\nTracing just-in-time compilation is a technique used by virtual machines to\noptimize the execution of a program at runtime. This is done by recording a\nlinear sequence of frequently executed operations, compiling them to native\nmachine code and executing them.\n\nFirst profiling information for loops is collected. After a hot loop has been\nidentified, a special tracing mode is entered which records all executed\noperations of that loop. This sequence of operations is called a **trace**.\nThe trace is then optimized and compiled to machine code. When this\nloop is executed again the compiled trace is called instead of the program\ncounterpart [#tracing_jit]_.\n\nWhy is tracing JIT important for us? The LuaJIT tracing compiler can detect\ntail-, up- and down-recursion [#luajit-recursion]_, unroll compositions of\nfunctions and inline high-order functions [#luajit-optimizations]_.\nAll of these concepts make the foundation for functional programming.\n\n.. [#iterators] http://en.wikipedia.org/wiki/Turtles_all_the_way_down\n.. [#lua_for] http://www.lua.org/manual/5.2/manual.html#3.3.5\n.. [#pure_function] http://en.wikipedia.org/wiki/Pure_function\n.. [#turing] `Proved by Turing <http://en.wikipedia.org/wiki/Halting_problem>`_\n.. [#tracing_jit] http://en.wikipedia.org/wiki/Tracing_just-in-time_compilation\n.. [#luajit-recursion] http://lambda-the-ultimate.org/node/3851#comment-57679\n.. [#luajit-optimizations] http://wiki.luajit.org/Optimizations\n"
  },
  {
    "path": "fun-scm-1.rockspec",
    "content": "package = \"fun\"\nversion = \"scm-1\"\n\nsource = {\n    url = \"git+https://github.com/luafun/luafun.git\",\n}\n\ndescription = {\n    summary = \"High-performance functional programming library for Lua\",\n    homepage = \"https://luafun.github.io/\",\n    license = \"MIT/X11\",\n    maintainer = \"Roman Tsisyk <roman@tarantool.org>\",\n    detailed = [[\nLua Fun is a high-performance functional programming library for Lua\ndesigned with LuaJIT's trace compiler in mind.\n\nLua Fun provides a set of more than 50 programming primitives typically\nfound in languages like Standard ML, Haskell, Erlang, JavaScript, Python and\neven Lisp. High-order functions such as map, filter, reduce, zip, etc.,\nmake it easy to write simple and efficient functional code.\n]]\n}\n\ndependencies = {\n    \"lua\"\n}\n\nbuild = {\n    type = \"builtin\",\n    modules = {\n        fun = \"fun.lua\",\n    },\n    copy_directories = { \"tests\" },\n}\n"
  },
  {
    "path": "fun.lua",
    "content": "---\n--- Lua Fun - a high-performance functional programming library for LuaJIT\n---\n--- Copyright (c) 2013-2017 Roman Tsisyk <roman@tsisyk.com>\n---\n--- Distributed under the MIT/X11 License. See COPYING.md for more details.\n---\n\nlocal exports = {}\nlocal methods = {}\n\n-- compatibility with Lua 5.1/5.2\nlocal unpack = rawget(table, \"unpack\") or unpack\n\n--------------------------------------------------------------------------------\n-- Tools\n--------------------------------------------------------------------------------\n\nlocal return_if_not_empty = function(state_x, ...)\n    if state_x == nil then\n        return nil\n    end\n    return ...\nend\n\nlocal call_if_not_empty = function(fun, state_x, ...)\n    if state_x == nil then\n        return nil\n    end\n    return state_x, fun(...)\nend\n\nlocal function deepcopy(orig) -- used by cycle()\n    local orig_type = type(orig)\n    local copy\n    if orig_type == 'table' then\n        copy = {}\n        for orig_key, orig_value in next, orig, nil do\n            copy[deepcopy(orig_key)] = deepcopy(orig_value)\n        end\n    else\n        copy = orig\n    end\n    return copy\nend\n\nlocal iterator_mt = {\n    -- usually called by for-in loop\n    __call = function(self, param, state)\n        return self.gen(param, state)\n    end;\n    __tostring = function(self)\n        return '<generator>'\n    end;\n    -- add all exported methods\n    __index = methods;\n}\n\nlocal wrap = function(gen, param, state)\n    return setmetatable({\n        gen = gen,\n        param = param,\n        state = state\n    }, iterator_mt), param, state\nend\nexports.wrap = wrap\n\nlocal unwrap = function(self)\n    return self.gen, self.param, self.state\nend\nmethods.unwrap = unwrap\n\n--------------------------------------------------------------------------------\n-- Basic Functions\n--------------------------------------------------------------------------------\n\nlocal nil_gen = function(_param, _state)\n    return nil\nend\n\nlocal string_gen = function(param, state)\n    local state = state + 1\n    if state > #param then\n        return nil\n    end\n    local r = string.sub(param, state, state)\n    return state, r\nend\n\nlocal ipairs_gen = ipairs({}) -- get the generating function from ipairs\n\nlocal pairs_gen = pairs({ a = 0 }) -- get the generating function from pairs\nlocal map_gen = function(tab, key)\n    local value\n    local key, value = pairs_gen(tab, key)\n    return key, key, value\nend\n\nlocal rawiter = function(obj, param, state)\n    assert(obj ~= nil, \"invalid iterator\")\n    if type(obj) == \"table\" then\n        local mt = getmetatable(obj);\n        if mt ~= nil then\n            if mt == iterator_mt then\n                return obj.gen, obj.param, obj.state\n            elseif mt.__ipairs ~= nil then\n                return mt.__ipairs(obj)\n            elseif mt.__pairs ~= nil then\n                return mt.__pairs(obj)\n            end\n        end\n        if #obj > 0 then\n            -- array\n            return ipairs(obj)\n        else\n            -- hash\n            return map_gen, obj, nil\n        end\n    elseif (type(obj) == \"function\") then\n        return obj, param, state\n    elseif (type(obj) == \"string\") then\n        if #obj == 0 then\n            return nil_gen, nil, nil\n        end\n        return string_gen, obj, 0\n    end\n    error(string.format('object %s of type \"%s\" is not iterable',\n          obj, type(obj)))\nend\n\nlocal iter = function(obj, param, state)\n    return wrap(rawiter(obj, param, state))\nend\nexports.iter = iter\n\nlocal method0 = function(fun)\n    return function(self)\n        return fun(self.gen, self.param, self.state)\n    end\nend\n\nlocal method1 = function(fun)\n    return function(self, arg1)\n        return fun(arg1, self.gen, self.param, self.state)\n    end\nend\n\nlocal method2 = function(fun)\n    return function(self, arg1, arg2)\n        return fun(arg1, arg2, self.gen, self.param, self.state)\n    end\nend\n\nlocal export0 = function(fun)\n    return function(gen, param, state)\n        return fun(rawiter(gen, param, state))\n    end\nend\n\nlocal export1 = function(fun)\n    return function(arg1, gen, param, state)\n        return fun(arg1, rawiter(gen, param, state))\n    end\nend\n\nlocal export2 = function(fun)\n    return function(arg1, arg2, gen, param, state)\n        return fun(arg1, arg2, rawiter(gen, param, state))\n    end\nend\n\nlocal each = function(fun, gen, param, state)\n    repeat\n        state = call_if_not_empty(fun, gen(param, state))\n    until state == nil\nend\nmethods.each = method1(each)\nexports.each = export1(each)\nmethods.for_each = methods.each\nexports.for_each = exports.each\nmethods.foreach = methods.each\nexports.foreach = exports.each\n\n--------------------------------------------------------------------------------\n-- Generators\n--------------------------------------------------------------------------------\n\nlocal range_gen = function(param, state)\n    local stop, step = param[1], param[2]\n    local state = state + step\n    if state > stop then\n        return nil\n    end\n    return state, state\nend\n\nlocal range_rev_gen = function(param, state)\n    local stop, step = param[1], param[2]\n    local state = state + step\n    if state < stop then\n        return nil\n    end\n    return state, state\nend\n\nlocal range = function(start, stop, step)\n    if step == nil then\n        if stop == nil then\n            if start == 0 then\n                return nil_gen, nil, nil\n            end\n            stop = start\n            start = stop > 0 and 1 or -1\n        end\n        step = start <= stop and 1 or -1\n    end\n\n    assert(type(start) == \"number\", \"start must be a number\")\n    assert(type(stop) == \"number\", \"stop must be a number\")\n    assert(type(step) == \"number\", \"step must be a number\")\n    assert(step ~= 0, \"step must not be zero\")\n\n    if (step > 0) then\n        return wrap(range_gen, {stop, step}, start - step)\n    elseif (step < 0) then\n        return wrap(range_rev_gen, {stop, step}, start - step)\n    end\nend\nexports.range = range\n\nlocal duplicate_table_gen = function(param_x, state_x)\n    return state_x + 1, unpack(param_x)\nend\n\nlocal duplicate_fun_gen = function(param_x, state_x)\n    return state_x + 1, param_x(state_x)\nend\n\nlocal duplicate_gen = function(param_x, state_x)\n    return state_x + 1, param_x\nend\n\nlocal duplicate = function(...)\n    if select('#', ...) <= 1 then\n        return wrap(duplicate_gen, select(1, ...), 0)\n    else\n        return wrap(duplicate_table_gen, {...}, 0)\n    end\nend\nexports.duplicate = duplicate\nexports.replicate = duplicate\nexports.xrepeat = duplicate\n\nlocal tabulate = function(fun)\n    assert(type(fun) == \"function\")\n    return wrap(duplicate_fun_gen, fun, 0)\nend\nexports.tabulate = tabulate\n\nlocal zeros = function()\n    return wrap(duplicate_gen, 0, 0)\nend\nexports.zeros = zeros\n\nlocal ones = function()\n    return wrap(duplicate_gen, 1, 0)\nend\nexports.ones = ones\n\nlocal rands_gen = function(param_x, _state_x)\n    return 0, math.random(param_x[1], param_x[2])\nend\n\nlocal rands_nil_gen = function(_param_x, _state_x)\n    return 0, math.random()\nend\n\nlocal rands = function(n, m)\n    if n == nil and m == nil then\n        return wrap(rands_nil_gen, 0, 0)\n    end\n    assert(type(n) == \"number\", \"invalid first arg to rands\")\n    if m == nil then\n        m = n\n        n = 0\n    else\n        assert(type(m) == \"number\", \"invalid second arg to rands\")\n    end\n    assert(n < m, \"empty interval\")\n    return wrap(rands_gen, {n, m - 1}, 0)\nend\nexports.rands = rands\n\n--------------------------------------------------------------------------------\n-- Slicing\n--------------------------------------------------------------------------------\n\nlocal nth = function(n, gen_x, param_x, state_x)\n    assert(n > 0, \"invalid first argument to nth\")\n    -- An optimization for arrays and strings\n    if gen_x == ipairs_gen then\n        return param_x[state_x + n]\n    elseif gen_x == string_gen then\n        if state_x + n <= #param_x then\n            return string.sub(param_x, state_x + n, state_x + n)\n        else\n            return nil\n        end\n    end\n    for i=1,n-1,1 do\n        state_x = gen_x(param_x, state_x)\n        if state_x == nil then\n            return nil\n        end\n    end\n    return return_if_not_empty(gen_x(param_x, state_x))\nend\nmethods.nth = method1(nth)\nexports.nth = export1(nth)\n\nlocal head_call = function(state, ...)\n    if state == nil then\n        error(\"head: iterator is empty\")\n    end\n    return ...\nend\n\nlocal head = function(gen, param, state)\n    return head_call(gen(param, state))\nend\nmethods.head = method0(head)\nexports.head = export0(head)\nexports.car = exports.head\nmethods.car = methods.head\n\nlocal tail = function(gen, param, state)\n    state = gen(param, state)\n    if state == nil then\n        return wrap(nil_gen, nil, nil)\n    end\n    return wrap(gen, param, state)\nend\nmethods.tail = method0(tail)\nexports.tail = export0(tail)\nexports.cdr = exports.tail\nmethods.cdr = methods.tail\n\nlocal take_n_gen_x = function(i, state_x, ...)\n    if state_x == nil then\n        return nil\n    end\n    return {i, state_x}, ...\nend\n\nlocal take_n_gen = function(param, state)\n    local n, gen_x, param_x = param[1], param[2], param[3]\n    local i, state_x = state[1], state[2]\n    if i >= n then\n        return nil\n    end\n    return take_n_gen_x(i + 1, gen_x(param_x, state_x))\nend\n\nlocal take_n = function(n, gen, param, state)\n    assert(n >= 0, \"invalid first argument to take_n\")\n    return wrap(take_n_gen, {n, gen, param}, {0, state})\nend\nmethods.take_n = method1(take_n)\nexports.take_n = export1(take_n)\n\nlocal take_while_gen_x = function(fun, state_x, ...)\n    if state_x == nil or not fun(...) then\n        return nil\n    end\n    return state_x, ...\nend\n\nlocal take_while_gen = function(param, state_x)\n    local fun, gen_x, param_x = param[1], param[2], param[3]\n    return take_while_gen_x(fun, gen_x(param_x, state_x))\nend\n\nlocal take_while = function(fun, gen, param, state)\n    assert(type(fun) == \"function\", \"invalid first argument to take_while\")\n    return wrap(take_while_gen, {fun, gen, param}, state)\nend\nmethods.take_while = method1(take_while)\nexports.take_while = export1(take_while)\n\nlocal take = function(n_or_fun, gen, param, state)\n    if type(n_or_fun) == \"number\" then\n        return take_n(n_or_fun, gen, param, state)\n    else\n        return take_while(n_or_fun, gen, param, state)\n    end\nend\nmethods.take = method1(take)\nexports.take = export1(take)\n\nlocal drop_n = function(n, gen, param, state)\n    assert(n >= 0, \"invalid first argument to drop_n\")\n    local i\n    for i=1,n,1 do\n        state = gen(param, state)\n        if state == nil then\n            return wrap(nil_gen, nil, nil)\n        end\n    end\n    return wrap(gen, param, state)\nend\nmethods.drop_n = method1(drop_n)\nexports.drop_n = export1(drop_n)\n\n-- Unpack values from param[3] on the first iteration, then return\n-- values from the provided iterator.\n--\n-- A generator function for drop_while().\nlocal drop_while_gen = function(param, state)\n    local results = param[3]\n    if not results then\n        return param[1](param[2], state)\n    else\n        param[3] = nil\n        return state, unpack(results, 1, table.maxn(results))\n    end\nend\n\n-- Checks if drop_while should continue skipping. If iterator is not exhausted\n-- and skipping is over, elements returned by iterator are wrapped into a table\n-- and returned as the second return value. Note that a table is created only\n-- once, on the last iteration, for the sake of performance.\nlocal drop_while_x = function(fun, state_x, ...)\n    if state_x ~= nil and not fun(...) then\n        return state_x, {...}\n    end\n    return state_x\nend\n\nlocal drop_while = function(fun, gen_x, param_x, state_x)\n    assert(type(fun) == \"function\", \"invalid first argument to drop_while\")\n    local pivot = nil\n    while state_x ~= nil and pivot == nil do\n        state_x, pivot = drop_while_x(fun, gen_x(param_x, state_x))\n    end\n    if state_x == nil then\n        return wrap(nil_gen, nil, nil)\n    end\n    return wrap(drop_while_gen, {gen_x, param_x, pivot}, state_x)\nend\nmethods.drop_while = method1(drop_while)\nexports.drop_while = export1(drop_while)\n\nlocal drop = function(n_or_fun, gen_x, param_x, state_x)\n    if type(n_or_fun) == \"number\" then\n        return drop_n(n_or_fun, gen_x, param_x, state_x)\n    else\n        return drop_while(n_or_fun, gen_x, param_x, state_x)\n    end\nend\nmethods.drop = method1(drop)\nexports.drop = export1(drop)\n\nlocal split = function(n_or_fun, gen_x, param_x, state_x)\n    return take(n_or_fun, gen_x, param_x, state_x),\n           drop(n_or_fun, gen_x, param_x, state_x)\nend\nmethods.split = method1(split)\nexports.split = export1(split)\nmethods.split_at = methods.split\nexports.split_at = exports.split\nmethods.span = methods.split\nexports.span = exports.split\n\n--------------------------------------------------------------------------------\n-- Indexing\n--------------------------------------------------------------------------------\n\nlocal index = function(x, gen, param, state)\n    local i = 1\n    for _k, r in gen, param, state do\n        if r == x then\n            return i\n        end\n        i = i + 1\n    end\n    return nil\nend\nmethods.index = method1(index)\nexports.index = export1(index)\nmethods.index_of = methods.index\nexports.index_of = exports.index\nmethods.elem_index = methods.index\nexports.elem_index = exports.index\n\nlocal indexes_gen = function(param, state)\n    local x, gen_x, param_x = param[1], param[2], param[3]\n    local i, state_x = state[1], state[2]\n    local r\n    while true do\n        state_x, r = gen_x(param_x, state_x)\n        if state_x == nil then\n            return nil\n        end\n        i = i + 1\n        if r == x then\n            return {i, state_x}, i\n        end\n    end\nend\n\nlocal indexes = function(x, gen, param, state)\n    return wrap(indexes_gen, {x, gen, param}, {0, state})\nend\nmethods.indexes = method1(indexes)\nexports.indexes = export1(indexes)\nmethods.elem_indexes = methods.indexes\nexports.elem_indexes = exports.indexes\nmethods.indices = methods.indexes\nexports.indices = exports.indexes\nmethods.elem_indices = methods.indexes\nexports.elem_indices = exports.indexes\n\n--------------------------------------------------------------------------------\n-- Filtering\n--------------------------------------------------------------------------------\n\nlocal filter1_gen = function(fun, gen_x, param_x, state_x, a)\n    while true do\n        if state_x == nil or fun(a) then break; end\n        state_x, a = gen_x(param_x, state_x)\n    end\n    return state_x, a\nend\n\n-- call each other\nlocal filterm_gen\nlocal filterm_gen_shrink = function(fun, gen_x, param_x, state_x)\n    return filterm_gen(fun, gen_x, param_x, gen_x(param_x, state_x))\nend\n\nfilterm_gen = function(fun, gen_x, param_x, state_x, ...)\n    if state_x == nil then\n        return nil\n    end\n    if fun(...) then\n        return state_x, ...\n    end\n    return filterm_gen_shrink(fun, gen_x, param_x, state_x)\nend\n\nlocal filter_detect = function(fun, gen_x, param_x, state_x, ...)\n    if select('#', ...) < 2 then\n        return filter1_gen(fun, gen_x, param_x, state_x, ...)\n    else\n        return filterm_gen(fun, gen_x, param_x, state_x, ...)\n    end\nend\n\nlocal filter_gen = function(param, state_x)\n    local fun, gen_x, param_x = param[1], param[2], param[3]\n    return filter_detect(fun, gen_x, param_x, gen_x(param_x, state_x))\nend\n\nlocal filter = function(fun, gen, param, state)\n    return wrap(filter_gen, {fun, gen, param}, state)\nend\nmethods.filter = method1(filter)\nexports.filter = export1(filter)\nmethods.remove_if = methods.filter\nexports.remove_if = exports.filter\n\nlocal grep = function(fun_or_regexp, gen, param, state)\n    local fun = fun_or_regexp\n    if type(fun_or_regexp) == \"string\" then\n        fun = function(x) return string.find(x, fun_or_regexp) ~= nil end\n    end\n    return filter(fun, gen, param, state)\nend\nmethods.grep = method1(grep)\nexports.grep = export1(grep)\n\nlocal partition = function(fun, gen, param, state)\n    local neg_fun = function(...)\n        return not fun(...)\n    end\n    return filter(fun, gen, param, state),\n           filter(neg_fun, gen, param, state)\nend\nmethods.partition = method1(partition)\nexports.partition = export1(partition)\n\n--------------------------------------------------------------------------------\n-- Reducing\n--------------------------------------------------------------------------------\n\nlocal foldl_call = function(fun, start, state, ...)\n    if state == nil then\n        return nil, start\n    end\n    return state, fun(start, ...)\nend\n\nlocal foldl = function(fun, start, gen_x, param_x, state_x)\n    while true do\n        state_x, start = foldl_call(fun, start, gen_x(param_x, state_x))\n        if state_x == nil then\n            break;\n        end\n    end\n    return start\nend\nmethods.foldl = method2(foldl)\nexports.foldl = export2(foldl)\nmethods.reduce = methods.foldl\nexports.reduce = exports.foldl\n\nlocal length = function(gen, param, state)\n    if gen == ipairs_gen or gen == string_gen then\n        return #param - state\n    end\n    local len = 0\n    repeat\n        state = gen(param, state)\n        len = len + 1\n    until state == nil\n    return len - 1\nend\nmethods.length = method0(length)\nexports.length = export0(length)\n\nlocal is_null = function(gen, param, state)\n    return gen(param, deepcopy(state)) == nil\nend\nmethods.is_null = method0(is_null)\nexports.is_null = export0(is_null)\n\nlocal is_prefix_of = function(iter_x, iter_y)\n    local gen_x, param_x, state_x = iter(iter_x)\n    local gen_y, param_y, state_y = iter(iter_y)\n\n    local r_x, r_y\n    repeat\n        state_x, r_x = gen_x(param_x, state_x)\n        if state_x == nil then\n            return true\n        end\n\n        state_y, r_y = gen_y(param_y, state_y)\n    until state_y == nil or r_x ~= r_y\n\n    return false\nend\nmethods.is_prefix_of = is_prefix_of\nexports.is_prefix_of = is_prefix_of\n\nlocal all = function(fun, gen_x, param_x, state_x)\n    local r\n    repeat\n        state_x, r = call_if_not_empty(fun, gen_x(param_x, state_x))\n    until state_x == nil or not r\n    return state_x == nil\nend\nmethods.all = method1(all)\nexports.all = export1(all)\nmethods.every = methods.all\nexports.every = exports.all\n\nlocal any = function(fun, gen_x, param_x, state_x)\n    local r\n    repeat\n        state_x, r = call_if_not_empty(fun, gen_x(param_x, state_x))\n    until state_x == nil or r\n    return not not r\nend\nmethods.any = method1(any)\nexports.any = export1(any)\nmethods.some = methods.any\nexports.some = exports.any\n\nlocal sum = function(gen, param, state)\n    local s = 0\n    local r = 0\n    repeat\n        s = s + r\n        state, r = gen(param, state)\n    until state == nil\n    return s\nend\nmethods.sum = method0(sum)\nexports.sum = export0(sum)\n\nlocal product = function(gen, param, state)\n    local p = 1\n    local r = 1\n    repeat\n        p = p * r\n        state, r = gen(param, state)\n    until state == nil\n    return p\nend\nmethods.product = method0(product)\nexports.product = export0(product)\n\nlocal min_cmp = function(m, n)\n    if n < m then return n else return m end\nend\n\nlocal max_cmp = function(m, n)\n    if n > m then return n else return m end\nend\n\nlocal min = function(gen, param, state)\n    local state, m = gen(param, state)\n    if state == nil then\n        error(\"min: iterator is empty\")\n    end\n\n    local cmp\n    if type(m) == \"number\" then\n        -- An optimization: use math.min for numbers\n        cmp = math.min\n    else\n        cmp = min_cmp\n    end\n\n    for _, r in gen, param, state do\n        m = cmp(m, r)\n    end\n    return m\nend\nmethods.min = method0(min)\nexports.min = export0(min)\nmethods.minimum = methods.min\nexports.minimum = exports.min\n\nlocal min_by = function(cmp, gen_x, param_x, state_x)\n    local state_x, m = gen_x(param_x, state_x)\n    if state_x == nil then\n        error(\"min: iterator is empty\")\n    end\n\n    for _, r in gen_x, param_x, state_x do\n        m = cmp(m, r)\n    end\n    return m\nend\nmethods.min_by = method1(min_by)\nexports.min_by = export1(min_by)\nmethods.minimum_by = methods.min_by\nexports.minimum_by = exports.min_by\n\nlocal max = function(gen_x, param_x, state_x)\n    local state_x, m = gen_x(param_x, state_x)\n    if state_x == nil then\n        error(\"max: iterator is empty\")\n    end\n\n    local cmp\n    if type(m) == \"number\" then\n        -- An optimization: use math.max for numbers\n        cmp = math.max\n    else\n        cmp = max_cmp\n    end\n\n    for _, r in gen_x, param_x, state_x do\n        m = cmp(m, r)\n    end\n    return m\nend\nmethods.max = method0(max)\nexports.max = export0(max)\nmethods.maximum = methods.max\nexports.maximum = exports.max\n\nlocal max_by = function(cmp, gen_x, param_x, state_x)\n    local state_x, m = gen_x(param_x, state_x)\n    if state_x == nil then\n        error(\"max: iterator is empty\")\n    end\n\n    for _, r in gen_x, param_x, state_x do\n        m = cmp(m, r)\n    end\n    return m\nend\nmethods.max_by = method1(max_by)\nexports.max_by = export1(max_by)\nmethods.maximum_by = methods.max_by\nexports.maximum_by = exports.max_by\n\nlocal totable = function(gen_x, param_x, state_x)\n    local tab, key, val = {}\n    while true do\n        state_x, val = gen_x(param_x, state_x)\n        if state_x == nil then\n            break\n        end\n        table.insert(tab, val)\n    end\n    return tab\nend\nmethods.totable = method0(totable)\nexports.totable = export0(totable)\n\nlocal tomap = function(gen_x, param_x, state_x)\n    local tab, key, val = {}\n    while true do\n        state_x, key, val = gen_x(param_x, state_x)\n        if state_x == nil then\n            break\n        end\n        tab[key] = val\n    end\n    return tab\nend\nmethods.tomap = method0(tomap)\nexports.tomap = export0(tomap)\n\n--------------------------------------------------------------------------------\n-- Transformations\n--------------------------------------------------------------------------------\n\nlocal map_gen = function(param, state)\n    local gen_x, param_x, fun = param[1], param[2], param[3]\n    return call_if_not_empty(fun, gen_x(param_x, state))\nend\n\nlocal map = function(fun, gen, param, state)\n    return wrap(map_gen, {gen, param, fun}, state)\nend\nmethods.map = method1(map)\nexports.map = export1(map)\n\nlocal enumerate_gen_call = function(state, i, state_x, ...)\n    if state_x == nil then\n        return nil\n    end\n    return {i + 1, state_x}, i, ...\nend\n\nlocal enumerate_gen = function(param, state)\n    local gen_x, param_x = param[1], param[2]\n    local i, state_x = state[1], state[2]\n    return enumerate_gen_call(state, i, gen_x(param_x, state_x))\nend\n\nlocal enumerate = function(gen, param, state)\n    return wrap(enumerate_gen, {gen, param}, {1, state})\nend\nmethods.enumerate = method0(enumerate)\nexports.enumerate = export0(enumerate)\n\nlocal intersperse_call = function(i, state_x, ...)\n    if state_x == nil then\n        return nil\n    end\n    return {i + 1, state_x}, ...\nend\n\nlocal intersperse_gen = function(param, state)\n    local x, gen_x, param_x = param[1], param[2], param[3]\n    local i, state_x = state[1], state[2]\n    if i % 2 == 1 then\n        return {i + 1, state_x}, x\n    else\n        return intersperse_call(i, gen_x(param_x, state_x))\n    end\nend\n\n-- TODO: interperse must not add x to the tail\nlocal intersperse = function(x, gen, param, state)\n    return wrap(intersperse_gen, {x, gen, param}, {0, state})\nend\nmethods.intersperse = method1(intersperse)\nexports.intersperse = export1(intersperse)\n\n--------------------------------------------------------------------------------\n-- Compositions\n--------------------------------------------------------------------------------\n\nlocal function zip_gen_r(param, state, state_new, ...)\n    if #state_new == #param / 2 then\n        return state_new, ...\n    end\n\n    local i = #state_new + 1\n    local gen_x, param_x = param[2 * i - 1], param[2 * i]\n    local state_x, r = gen_x(param_x, state[i])\n    if state_x == nil then\n        return nil\n    end\n    table.insert(state_new, state_x)\n    return zip_gen_r(param, state, state_new, r, ...)\nend\n\nlocal zip_gen = function(param, state)\n    return zip_gen_r(param, state, {})\nend\n\n-- A special hack for zip/chain to skip last two state, if a wrapped iterator\n-- has been passed\nlocal numargs = function(...)\n    local n = select('#', ...)\n    if n >= 3 then\n        -- Fix last argument\n        local it = select(n - 2, ...)\n        if type(it) == 'table' and getmetatable(it) == iterator_mt and\n           it.param == select(n - 1, ...) and it.state == select(n, ...) then\n            return n - 2\n        end\n    end\n    return n\nend\n\nlocal zip = function(...)\n    local n = numargs(...)\n    if n == 0 then\n        return wrap(nil_gen, nil, nil)\n    end\n    local param = { [2 * n] = 0 }\n    local state = { [n] = 0 }\n\n    local i, gen_x, param_x, state_x\n    for i=1,n,1 do\n        local it = select(n - i + 1, ...)\n        gen_x, param_x, state_x = rawiter(it)\n        param[2 * i - 1] = gen_x\n        param[2 * i] = param_x\n        state[i] = state_x\n    end\n\n    return wrap(zip_gen, param, state)\nend\nmethods.zip = zip\nexports.zip = zip\n\nlocal cycle_gen_call = function(param, state_x, ...)\n    if state_x == nil then\n        local gen_x, param_x, state_x0 = param[1], param[2], param[3]\n        return gen_x(param_x, deepcopy(state_x0))\n    end\n    return state_x, ...\nend\n\nlocal cycle_gen = function(param, state_x)\n    local gen_x, param_x, state_x0 = param[1], param[2], param[3]\n    return cycle_gen_call(param, gen_x(param_x, state_x))\nend\n\nlocal cycle = function(gen, param, state)\n    return wrap(cycle_gen, {gen, param, state}, deepcopy(state))\nend\nmethods.cycle = method0(cycle)\nexports.cycle = export0(cycle)\n\n-- call each other\nlocal chain_gen_r1\nlocal chain_gen_r2 = function(param, state, state_x, ...)\n    if state_x == nil then\n        local i = state[1]\n        i = i + 1\n        if param[3 * i - 2] == nil then\n            return nil\n        end\n        local state_x = param[3 * i]\n        return chain_gen_r1(param, {i, state_x})\n    end\n    return {state[1], state_x}, ...\nend\n\nchain_gen_r1 = function(param, state)\n    local i, state_x = state[1], state[2]\n    local gen_x, param_x = param[3 * i - 2], param[3 * i - 1]\n    return chain_gen_r2(param, state, gen_x(param_x, state[2]))\nend\n\nlocal chain = function(...)\n    local n = numargs(...)\n    if n == 0 then\n        return wrap(nil_gen, nil, nil)\n    end\n\n    local param = { [3 * n] = 0 }\n    local i, gen_x, param_x, state_x\n    for i=1,n,1 do\n        local elem = select(i, ...)\n        gen_x, param_x, state_x = iter(elem)\n        param[3 * i - 2] = gen_x\n        param[3 * i - 1] = param_x\n        param[3 * i] = state_x\n    end\n\n    return wrap(chain_gen_r1, param, {1, param[3]})\nend\nmethods.chain = chain\nexports.chain = chain\n\n--------------------------------------------------------------------------------\n-- Operators\n--------------------------------------------------------------------------------\n\nlocal operator = {\n    ----------------------------------------------------------------------------\n    -- Comparison operators\n    ----------------------------------------------------------------------------\n    lt  = function(a, b) return a < b end,\n    le  = function(a, b) return a <= b end,\n    eq  = function(a, b) return a == b end,\n    ne  = function(a, b) return a ~= b end,\n    ge  = function(a, b) return a >= b end,\n    gt  = function(a, b) return a > b end,\n\n    ----------------------------------------------------------------------------\n    -- Arithmetic operators\n    ----------------------------------------------------------------------------\n    add = function(a, b) return a + b end,\n    div = function(a, b) return a / b end,\n    floordiv = function(a, b) return math.floor(a/b) end,\n    intdiv = function(a, b)\n        local q = a / b\n        if a >= 0 then return math.floor(q) else return math.ceil(q) end\n    end,\n    mod = function(a, b) return a % b end,\n    mul = function(a, b) return a * b end,\n    neq = function(a) return -a end,\n    unm = function(a) return -a end, -- an alias\n    pow = function(a, b) return a ^ b end,\n    sub = function(a, b) return a - b end,\n    truediv = function(a, b) return a / b end,\n\n    ----------------------------------------------------------------------------\n    -- String operators\n    ----------------------------------------------------------------------------\n    concat = function(a, b) return a..b end,\n    len = function(a) return #a end,\n    length = function(a) return #a end, -- an alias\n\n    ----------------------------------------------------------------------------\n    -- Logical operators\n    ----------------------------------------------------------------------------\n    land = function(a, b) return a and b end,\n    lor = function(a, b) return a or b end,\n    lnot = function(a) return not a end,\n    truth = function(a) return not not a end,\n}\nexports.operator = operator\nmethods.operator = operator\nexports.op = operator\nmethods.op = operator\n\n--------------------------------------------------------------------------------\n-- module definitions\n--------------------------------------------------------------------------------\n\n-- a special syntax sugar to export all functions to the global table\nsetmetatable(exports, {\n    __call = function(t, override)\n        for k, v in pairs(t) do\n            if rawget(_G, k) ~= nil then\n                local msg = 'function ' .. k .. ' already exists in global scope.'\n                if override then\n                    rawset(_G, k, v)\n                    print('WARNING: ' .. msg .. ' Overwritten.')\n                else\n                    print('NOTICE: ' .. msg .. ' Skipped.')\n                end\n            else\n                rawset(_G, k, v)\n            end\n        end\n    end,\n})\n\nreturn exports\n"
  },
  {
    "path": "rpm/lua-fun.spec",
    "content": "%define luaver 5.3\n%define luapkgdir %{_datadir}/lua/%{luaver}\n# LuaJIT is compatible with Lua 5.1 and uses the same directory for modules\n%global ljpkgdir %{_datadir}/lua/5.1\n\nName: lua-fun\nVersion: 0.1.3\nRelease: 1%{?dist}\nSummary: Functional programming library for Lua\nGroup: Development/Libraries\nLicense: MIT\nURL: https://github.com/luafun/luafun\nSource0: https://github.com/luafun/luafun/archive/%{version}/luafun-%{version}.tar.gz\nBuildArch: noarch\nBuildRequires: luajit >= 2.0\nBuildRequires: lua >= 5.1\nRequires: lua >= 5.1\n\n%package -n luajit-fun\nSummary: Functional programming library for LuaJIT\nRequires: luajit >= 2.0\n\n%description -n lua-fun\nLua Fun is a high-performance functional programming library for Lua\ndesigned with LuaJIT's trace compiler in mind.\n\nLua Fun provides a set of more than 50 programming primitives typically\nfound in languages like Standard ML, Haskell, Erlang, JavaScript, Python and\neven Lisp. High-order functions such as map, filter, reduce, zip, etc.,\nmake it easy to write simple and efficient functional code.\n\nThis package provides a module for Lua %{luaver}.\n\n%description -n luajit-fun\nLua Fun is a high-performance functional programming library for Lua\ndesigned with LuaJIT's trace compiler in mind.\n\nLua Fun provides a set of more than 50 programming primitives typically\nfound in languages like Standard ML, Haskell, Erlang, JavaScript, Python and\neven Lisp. High-order functions such as map, filter, reduce, zip, etc.,\nmake it easy to write simple and efficient functional code.\n\nThis package provides a module for LuaJIT.\n\n%prep\n%setup -q -n luafun-%{version}\n\n%build\n# nothing to do\n\n%install\n# Install for Lua\nmkdir -p %{buildroot}%{luapkgdir}\ncp -av fun.lua %{buildroot}%{luapkgdir}/fun.lua\n# Install for LuaJIT\nmkdir -p %{buildroot}%{ljpkgdir}\ncp -av fun.lua %{buildroot}%{ljpkgdir}/fun.lua\n\n%check\ncd tests\nluajit ./runtest *.lua\nlua ./runtest *.lua\n\n%files -n lua-fun\n%{luapkgdir}/fun.lua\n%doc README.md CONTRIBUTING.md\n%license COPYING.md\n\n%files -n luajit-fun\n%{ljpkgdir}/fun.lua\n%doc README.md CONTRIBUTING.md\n%license COPYING.md\n\n%changelog\n* Mon Jan 18 2016 Roman Tsisyk <roman@tarantool.org> - 0.1.3-1\n- Initial version.\n"
  },
  {
    "path": "tests/.gitignore",
    "content": "*.new\n"
  },
  {
    "path": "tests/basic.lua",
    "content": "--------------------------------------------------------------------------------\n-- iter\n--------------------------------------------------------------------------------\n\n--\n-- Arrays\n--\n\nfor _it, a in iter({1, 2, 3}) do print(a) end\n--[[test\n1\n2\n3\n--test]]\n\nfor _it, a in iter(iter(iter({1, 2, 3}))) do print(a) end\n--[[test\n1\n2\n3\n--test]]\n\nfor _it, a in wrap(wrap(iter({1, 2, 3}))) do print(a) end\n--[[test\n1\n2\n3\n--test]]\n\nfor _it, a in wrap(wrap(ipairs({1, 2, 3}))) do print(a) end\n--[[test\n1\n2\n3\n--test]]\n\nfor _it, a in iter({}) do print(a) end\n--[[test\n--test]]\n\nfor _it, a in iter(iter(iter({}))) do print(a) end\n--[[test\n--test]]\n\nfor _it, a in wrap(wrap(iter({}))) do print(a) end\n--[[test\n--test]]\n\nfor _it, a in wrap(wrap(ipairs({}))) do print(a) end\n--[[test\n--test]]\n\n-- Check that ``iter`` for arrays is equivalent to ``ipairs``\nlocal t = {1, 2, 3}\ngen1, param1, state1 = iter(t):unwrap()\ngen2, param2, state2 = ipairs(t) \nprint(gen1 == gen2, param1 == param2, state1 == state2)\n--[[test\ntrue true true\n--test]]\n\n-- Test that ``wrap`` do nothing for wrapped iterators\ngen1, param1, state1 = iter({1, 2, 3})\ngen2, param2, state2 = wrap(gen1, param1, state1):unwrap()\nprint(gen1 == gen2, param1 == param2, state1 == state2)\n--[[test\ntrue true true\n--test]]\n\n--\n-- Maps\n--\n\nlocal t = {}\nfor _it, k, v in iter({ a = 1, b = 2, c = 3}) do t[#t + 1] = k end\ntable.sort(t)\nfor _it, v in iter(t) do print(v) end\n--[[test\na\nb\nc\n--test]]\n\nlocal t = {}\nfor _it, k, v in iter(iter(iter({ a = 1, b = 2, c = 3}))) do t[#t + 1] = k end\ntable.sort(t)\nfor _it, v in iter(t) do print(v) end\n--[[test\na\nb\nc\n--test]]\n\nfor _it, k, v in iter({}) do print(k, v) end\n--[[test\n--test]]\n\nfor _it, k, v in iter(iter(iter({}))) do print(k, v) end\n--[[test\n--test]]\n\n--\n-- String\n--\n\nfor _it, a in iter(\"abcde\") do print(a) end\n--[[test\na\nb\nc\nd\ne\n--test]]\n\nfor _it, a in iter(iter(iter(\"abcde\"))) do print(a) end\n--[[test\na\nb\nc\nd\ne\n--test]]\n\nfor _it, a in iter(\"\") do print(a) end\n--[[test\n--test]]\n\nfor _it, a in iter(iter(iter(\"\"))) do print(a) end\n--[[test\n--test]]\n\n--\n-- Custom generators\n--\n\nlocal function mypairs_gen(max, state)\n    if (state >= max) then\n            return nil\n        end\n        return state + 1, state + 1\nend\n\nlocal function mypairs(max)\n    return mypairs_gen, max, 0\nend\n\nfor _it, a in iter(mypairs(10)) do print(a) end\n--[[test\n1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n--test]]\n\n--\n-- Invalid values\n--\n\nfor _it, a in iter(1) do print(a) end\n--[[test\nerror: object 1 of type \"number\" is not iterable\n--test]]\n\nfor _it, a in iter(1, 2, 3, 4, 5, 6, 7) do print(a) end\n--[[test\nerror: object 1 of type \"number\" is not iterable\n--test]]\n\n--------------------------------------------------------------------------------\n-- each\n--------------------------------------------------------------------------------\n\neach(print, {1, 2, 3})\n--[[test\n1\n2\n3\n--test]]\n\neach(print, iter({1, 2, 3}))\n--[[test\n1\n2\n3\n--test]]\n\neach(print, {})\n--[[test\n--test]]\n\n\neach(print, iter({}))\n--[[test\n--test]]\n\nlocal keys, vals = {}, {}\neach(function(k, v)\n    keys[#keys + 1] = k\n    vals[#vals + 1] = v\nend, { a = 1, b = 2, c = 3})\ntable.sort(keys)\ntable.sort(vals)\neach(print, keys)\neach(print, vals)\n--[[test\na\nb\nc\n1\n2\n3\n--test]]\n\neach(print, \"abc\")\n--[[test\na\nb\nc\n--test]]\n\neach(print, iter(\"abc\"))\n--[[test\na\nb\nc\n--test]]\n\nprint(for_each == each) -- an alias\n--[[test\ntrue\n--test]]\n\nprint(foreach == each) -- an alias\n--[[test\ntrue\n--test]]\n\n--------------------------------------------------------------------------------\n-- totable\n--------------------------------------------------------------------------------\n\nlocal tab = totable(range(5))\nprint(type(tab), #tab)\neach(print, tab)\n--[[test\ntable 5\n1\n2\n3\n4\n5\n--test]]\n\nlocal tab = totable(range(0))\nprint(type(tab), #tab)\n--[[test\ntable 0\n--test]]\n\nlocal tab = totable(\"abcdef\")\nprint(type(tab), #tab)\neach(print, tab)\n--[[test\ntable 6\na\nb\nc\nd\ne\nf\n--test]]\n\nlocal unpack = rawget(table, \"unpack\") or unpack\nlocal tab = totable({ 'a', {'b', 'c'}, {'d', 'e', 'f'}})\nprint(type(tab), #tab)\neach(print, tab[1])\neach(print, map(unpack, drop(1, tab)))\n--[[test\ntable 3\na\nb c\nd e f\n--test]]\n\n--------------------------------------------------------------------------------\n-- tomap\n--------------------------------------------------------------------------------\n\nlocal tab = tomap(zip(range(1, 7), 'abcdef'))\nprint(type(tab), #tab)\neach(print, iter(tab))\n--[[test\ntable 6\na\nb\nc\nd\ne\nf\n--test]]\n\nlocal tab = tomap({a = 1, b = 2, c = 3})\nprint(type(tab), #tab)\nlocal t = {}\nfor _it, k, v in iter(tab) do t[v] = k end\ntable.sort(t)\nfor k, v in ipairs(t) do print(k, v) end\n--[[test\ntable 0\n1 a\n2 b\n3 c\n--test]]\n\nlocal tab = tomap(enumerate(\"abcdef\"))\nprint(type(tab), #tab)\neach(print, tab)\n--[[test\ntable 6\na\nb\nc\nd\ne\nf\n--test]]\n"
  },
  {
    "path": "tests/compositions.lua",
    "content": "--------------------------------------------------------------------------------\n-- zip\n--------------------------------------------------------------------------------\n\ndump(zip({\"a\", \"b\", \"c\", \"d\"}, {\"one\", \"two\", \"three\"}))\n--[[test\na one\nb two\nc three\n--test]]\n\ndump(zip())\n--[[test\n--test]]\n\ndump(zip(range(0)))\n--[[test\nerror: invalid iterator\n--test]]\n\ndump(zip(range(0), range(0)))\n--[[test\nerror: invalid iterator\n--test]]\n\nprint(nth(10, zip(range(1, 100, 3), range(1, 100, 5), range(1, 100, 7))))\n--[[test\n28 46 64\n--test]]\n\ndump(zip(partition(function(x) return x > 7 end, range(1, 15, 1))))\n--[[test\n8 1\n9 2\n10 3\n11 4\n12 5\n13 6\n14 7\n--test]]\n\n--------------------------------------------------------------------------------\n-- cycle\n--------------------------------------------------------------------------------\n\ndump(take(15, cycle({\"a\", \"b\", \"c\", \"d\", \"e\"})))\n--[[test\na\nb\nc\nd\ne\na\nb\nc\nd\ne\na\nb\nc\nd\ne\n--test]]\n\n\ndump(take(15, cycle(range(5))))\n--[[test\n1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n--test]]\n\ndump(take(15, cycle(zip(range(5), {\"a\", \"b\", \"c\", \"d\", \"e\"}))))\n--[[test\n1 a\n2 b\n3 c\n4 d\n5 e\n1 a\n2 b\n3 c\n4 d\n5 e\n1 a\n2 b\n3 c\n4 d\n5 e\n--test]]\n\n--------------------------------------------------------------------------------\n-- chain\n--------------------------------------------------------------------------------\n\ndump(chain(range(2)))\n--[[test\n1\n2\n--test]]\n\ndump(chain(range(2), {\"a\", \"b\", \"c\"}, {\"one\", \"two\", \"three\"}))\n--[[test\n1\n2\na\nb\nc\none\ntwo\nthree\n--test]]\n\ndump(take(15, cycle(chain(enumerate({\"a\", \"b\", \"c\"}),\n    {\"one\", \"two\", \"three\"}))))\n--[[test\n1 a\n2 b\n3 c\none\ntwo\nthree\n1 a\n2 b\n3 c\none\ntwo\nthree\n1 a\n2 b\n3 c\n--test]]\n\nlocal tab = {}\nlocal keys = {}\nfor _it, k, v in chain({ a = 11, b = 12, c = 13}, { d = 21, e = 22 }) do\n    tab[k] = v\n    table.insert(keys, k)\nend\ntable.sort(keys)\nfor _, key in ipairs(keys) do print(key, tab[key]) end\n--[[test\na 11\nb 12\nc 13\nd 21\ne 22\n--test]]\n\ndump(chain(range(0), range(0), range(0)))\n--[[test\nerror: invalid iterator\n--test]]\n\ndump(chain(range(0), range(1), range(0)))\n--[[test\nerror: invalid iterator\n--test]]\n\n-- Similar to fun.range(), but accepts just 'stop' for simplicity.\n--\n-- The key point of this iterator generator is that it doesn't use\n-- 'param' (the second value in the gen-param-state triplet) and\n-- pass nil to it. This is needed to reproduce the next scenario.\nfunction myrange(stop)\n    local function gen(_param, i)\n        if i < stop then\n            return i + 1, i + 1\n        end\n        return nil\n    end\n    return wrap(gen, nil, 0)\nend\n\n-- gh-86: verify that chain don't stop on an iterator that uses\n-- param = nil.\ndump(chain(myrange(3), myrange(3), myrange(3)))\n--[[test\n1\n2\n3\n1\n2\n3\n1\n2\n3\n--test]]\n"
  },
  {
    "path": "tests/filtering.lua",
    "content": "--------------------------------------------------------------------------------\n-- filter\n--------------------------------------------------------------------------------\n\ndump(filter(function(x) return x % 3 == 0 end, range(10)))\n--[[test\n3\n6\n9\n--test]]\n\ndump(filter(function(x) return x % 3 == 0 end, range(0)))\n--[[test\n--test]]\n\n\ndump(take(5, filter(function(i, x) return i % 3 == 0 end,\n    enumerate(duplicate('x')))))\n--[[test\n3 x\n6 x\n9 x\n12 x\n15 x\n--test]]\n\nfunction filter_fun(a, b, c)\n    if a % 16 == 0 then\n        return true\n    else\n        return false\n    end\nend\n\nfunction test3(a, b, c)\n    return a, c, b\nend\n\nn = 50\ndump(filter(filter_fun, map(test3, zip(range(0, n, 1),\n     range(0, n, 2), range(0, n, 3)))))\n--[[test\n0 0 0\n16 48 32\n--test]]\n\nprint(remove_if == filter) -- an alias\n--[[test\ntrue\n--test]]\n\ndump_state(filter(function(x) return x % 2 == 0 end, ipairs({0, 1, 1, 2, 3, 4})))\n--[[test\n1\n4\n6\n--test]]\n\n--------------------------------------------------------------------------------\n-- grep\n--------------------------------------------------------------------------------\n\nlines_to_grep = {\n    [[Lorem ipsum dolor sit amet, consectetur adipisicing elit, ]],\n    [[sed do eiusmod tempor incididunt ut labore et dolore magna ]],\n    [[aliqua. Ut enim ad minim veniam, quis nostrud exercitation ]],\n    [[ullamco laboris nisi ut aliquip ex ea commodo consequat.]],\n    [[Duis aute irure dolor in reprehenderit in voluptate velit ]],\n    [[esse cillum dolore eu fugiat nulla pariatur. Excepteur sint ]],\n    [[occaecat cupidatat non proident, sunt in culpa qui officia ]],\n    [[deserunt mollit anim id est laborum.]]\n}\n\ndump(grep(\"lab\", lines_to_grep))\n--[[test\nsed do eiusmod tempor incididunt ut labore et dolore magna \nullamco laboris nisi ut aliquip ex ea commodo consequat.\ndeserunt mollit anim id est laborum.\n--test]]\n\nlines_to_grep = {\n    [[Emily]],\n    [[Chloe]],\n    [[Megan]],\n    [[Jessica]],\n    [[Emma]],\n    [[Sarah]],\n    [[Elizabeth]],\n    [[Sophie]],\n    [[Olivia]],\n    [[Lauren]]\n}\n\ndump(grep(\"^Em\", lines_to_grep))\n--[[test\nEmily\nEmma\n--test]]\n\ndump_state(grep(\"^Em\", lines_to_grep))\n--[[test\n1\n5\n--test]]\n\n--------------------------------------------------------------------------------\n-- partition\n--------------------------------------------------------------------------------\n\ndump(zip(partition(function(i, x) return i % 3 == 0 end, range(10))))\n--[[test\n3 1\n6 2\n9 4\n--test]]\n"
  },
  {
    "path": "tests/generators.lua",
    "content": "--------------------------------------------------------------------------------\n-- range\n--------------------------------------------------------------------------------\n\ndump(range(0))\nprint('--')\nfor i=1,0 do print(i) end\n--[[test\n--\n--test]]\n\ndump(range(0, 0))\nprint('--')\nfor i=0,0 do print(i) end\n--[[test\n0\n--\n0\n--test]]\n\ndump(range(5))\nprint('--')\nfor i=1,5 do print(i) end\n--[[test\n1\n2\n3\n4\n5\n--\n1\n2\n3\n4\n5\n--test]]\n\ndump(range(0, 5))\nprint('--')\nfor i=0,5 do print(i) end\n--[[test\n0\n1\n2\n3\n4\n5\n--\n0\n1\n2\n3\n4\n5\n--test]]\n\ndump(range(0, 5, 1))\nprint('--')\nfor i=0,5,1 do print(i) end\n--[[test\n0\n1\n2\n3\n4\n5\n--\n0\n1\n2\n3\n4\n5\n--test]]\n\ndump(range(0, 10, 2))\nprint('--')\nfor i=0,10,2 do print(i) end\n--[[test\n0\n2\n4\n6\n8\n10\n--\n0\n2\n4\n6\n8\n10\n--test]]\n\ndump(range(-5))\nprint('--')\nfor i=-1,-5,-1 do print(i) end\n--[[test\n-1\n-2\n-3\n-4\n-5\n--\n-1\n-2\n-3\n-4\n-5\n--test]]\n\ndump(range(0, -5, 1))\nprint('--')\nfor i=0,-5,1 do print(i) end\n--[[test\n--\n--test]]\n\ndump(range(0, -5, -1))\nprint('--')\nfor i=0,-5,-1 do print(i) end\n--[[test\n0\n-1\n-2\n-3\n-4\n-5\n--\n0\n-1\n-2\n-3\n-4\n-5\n--test]]\n\ndump(range(0, -10, -2))\nprint('--')\nfor i=0,-10,-2 do print(i) end\n--[[test\n0\n-2\n-4\n-6\n-8\n-10\n--\n0\n-2\n-4\n-6\n-8\n-10\n--test]]\n\ndump(range(1.2, 1.6, 0.1))\n--[[test\n1.2\n1.3\n1.4\n1.5\n--test]]\n\n-- Invalid step\ndump(range(0, 5, 0))\n--[[test\nerror: step must not be zero\n--test]]\n\n--------------------------------------------------------------------------------\n-- duplicate\n--------------------------------------------------------------------------------\n\ndump(take(5, duplicate(48)))\n--[[test\n48\n48\n48\n48\n48\n--test]]\n\ndump(take(5, duplicate(1,2,3,4,5)))\n--[[test\n1 2 3 4 5\n1 2 3 4 5\n1 2 3 4 5\n1 2 3 4 5\n1 2 3 4 5\n--test]]\n\nprint(xrepeat == duplicate) -- an alias\n--[[test\ntrue\n--test]]\n\nprint(replicate == duplicate) -- an alias\n--[[test\ntrue\n--test]]\n\n--------------------------------------------------------------------------------\n-- tabulate\n--------------------------------------------------------------------------------\n\ndump(take(5, tabulate(function(x) return 2 * x end)))\n--[[test\n0\n2\n4\n6\n8\n--test]]\n\n--------------------------------------------------------------------------------\n-- zeros\n--------------------------------------------------------------------------------\n\ndump(take(5, zeros()))\n--[[test\n0\n0\n0\n0\n0\n--test]]\n\n--------------------------------------------------------------------------------\n-- ones\n--------------------------------------------------------------------------------\n\ndump(take(5, ones()))\n--[[test\n1\n1\n1\n1\n1\n--test]]\n\n--------------------------------------------------------------------------------\n-- rands\n--------------------------------------------------------------------------------\n\nprint(all(function(x) return x >= 0 and x < 1 end, take(5, rands())))\n--[[test\ntrue\n--test]]\n\ndump(take(5, rands(0)))\n--[[test\nerror: empty interval\n--test]]\n\nprint(all(function(x) return math.floor(x) == x end, take(5, rands(10))))\n--[[test\ntrue\n--test]]\n\nprint(all(function(x) return math.floor(x) == x end, take(5, rands(1024))))\n--[[test\ntrue\n--test]]\n\ndump(take(5, rands(0, 1)))\n--[[test\n0\n0\n0\n0\n0\n--test]]\n\ndump(take(5, rands(5, 6)))\n--[[test\n5\n5\n5\n5\n5\n--test]]\n\nprint(all(function(x) return x >= 10 and x < 20 end, take(20, rands(10, 20))))\n--[[test\ntrue\n--test]]\n"
  },
  {
    "path": "tests/indexing.lua",
    "content": "--------------------------------------------------------------------------------\n-- index\n--------------------------------------------------------------------------------\n\nprint(index(2, range(5)))\n--[[test\n2\n--test]]\n\nprint(index(10, range(5)))\n--[[test\nnil\n--test]]\n\nprint(index(2, range(0)))\n--[[test\nnil\n--test]]\n\nprint(index(\"b\", {\"a\", \"b\", \"c\", \"d\", \"e\"}))\n--[[test\n2\n--test]]\n\nprint(index(1, enumerate({\"a\", \"b\", \"c\", \"d\", \"e\"})))\n--[[test\n1\n--test]]\n\nprint(index(\"b\", \"abcdef\"))\n--[[test\n2\n--test]]\n\nprint(index_of == index) -- an alias\n--[[test\ntrue\n--test]]\n\nprint(elem_index == index) -- an alias\n--[[test\ntrue\n--test]]\n\n--------------------------------------------------------------------------------\n-- indexes\n--------------------------------------------------------------------------------\n\ndump(indexes(\"a\", {\"a\", \"b\", \"c\", \"d\", \"e\", \"a\", \"b\", \"c\", \"d\", \"a\", \"a\"}))\n--[[test\n1\n6\n10\n11\n--test]]\n\ndump(indexes(\"f\", {\"a\", \"b\", \"c\", \"d\", \"e\", \"a\", \"b\", \"c\", \"d\", \"a\", \"a\"}))\n--[[test\n--test]]\n\ndump(indexes(\"f\", {}))\n--[[test\n--test]]\n\ndump(indexes(1, enumerate({\"a\", \"b\", \"c\", \"d\", \"e\"})))\n--[[test\n1\n--test]]\n\nprint(indices == indexes) -- an alias\n--[[test\ntrue\n--test]]\n\nprint(elem_indexes == indexes) -- an alias\n--[[test\ntrue\n--test]]\n\nprint(elem_indices == indexes) -- an alias\n--[[test\ntrue\n--test]]\n"
  },
  {
    "path": "tests/operators.lua",
    "content": "--\n-- All these functions are fully covered by Lua tests.\n-- This test just checks that all functions were defined correctly.\n--\n\nprint(op == operator) -- an alias\n--[[test\ntrue\n--test]]\n\n--------------------------------------------------------------------------------\n-- Comparison operators\n--------------------------------------------------------------------------------\n\nlocal comparators = { 'le', 'lt', 'eq', 'ne', 'ge', 'gt' }\nfor _k, op in iter(comparators) do\n    print('op', op)\n    print('==')\n    print('num:')\n    print(operator[op](0, 1))\n    print(operator[op](1, 0))\n    print(operator[op](0, 0))\n    print('str:')\n    print(operator[op](\"abc\", \"cde\"))\n    print(operator[op](\"cde\", \"abc\"))\n    print(operator[op](\"abc\", \"abc\"))\n    print('')\nend\n--[[test\nop le\n==\nnum:\ntrue\nfalse\ntrue\nstr:\ntrue\nfalse\ntrue\n\nop lt\n==\nnum:\ntrue\nfalse\nfalse\nstr:\ntrue\nfalse\nfalse\n\nop eq\n==\nnum:\nfalse\nfalse\ntrue\nstr:\nfalse\nfalse\ntrue\n\nop ne\n==\nnum:\ntrue\ntrue\nfalse\nstr:\ntrue\ntrue\nfalse\n\nop ge\n==\nnum:\nfalse\ntrue\ntrue\nstr:\nfalse\ntrue\ntrue\n\nop gt\n==\nnum:\nfalse\ntrue\nfalse\nstr:\nfalse\ntrue\nfalse\n\n--test]]\n\n--------------------------------------------------------------------------------\n-- Arithmetic operators\n--------------------------------------------------------------------------------\n\nprint(operator.add(-1.0, 1.0))\nprint(operator.add(0, 0))\nprint(operator.add(12, 2))\n--[[test\n0\n0\n14\n--test]]\n\nprint(operator.div(10, 2))\nprint(operator.div(10, 3))\nprint(operator.div(-10, 3))\n--[[test\n5\n3.3333333333333\n-3.3333333333333\n--test]]\n\nprint(operator.floordiv(10, 3))\nprint(operator.floordiv(11, 3))\nprint(operator.floordiv(12, 3))\nprint(operator.floordiv(-10, 3))\nprint(operator.floordiv(-11, 3))\nprint(operator.floordiv(-12, 3))\n--[[test\n3\n3\n4\n-4\n-4\n-4\n--test]]\n\nprint(operator.intdiv(10, 3))\nprint(operator.intdiv(11, 3))\nprint(operator.intdiv(12, 3))\nprint(operator.intdiv(-10, 3))\nprint(operator.intdiv(-11, 3))\nprint(operator.intdiv(-12, 3))\n--[[test\n3\n3\n4\n-3\n-3\n-4\n--test]]\n\nprint(operator.truediv(10, 3))\nprint(operator.truediv(11, 3))\nprint(operator.truediv(12, 3))\nprint(operator.truediv(-10, 3))\nprint(operator.truediv(-11, 3))\nprint(operator.truediv(-12, 3))\n--[[test\n3.3333333333333\n3.6666666666667\n4\n-3.3333333333333\n-3.6666666666667\n-4\n--test]]\n\nprint(operator.mod(10, 2))\nprint(operator.mod(10, 3))\nprint(operator.mod(-10, 3))\n--[[test\n0\n1\n2\n--test]]\n\nprint(operator.mul(10, 0.1))\nprint(operator.mul(0, 0))\nprint(operator.mul(-1, -1))\n--[[test\n1\n0\n1\n--test]]\n\nprint(operator.neq(1))\nprint(operator.neq(0) == 0)\nprint(operator.neq(-0) == 0)\nprint(operator.neq(-1))\n--[[test\n-1\ntrue\ntrue\n1\n--test]]\n\nprint(operator.unm(1))\nprint(operator.unm(0) == 0)\nprint(operator.unm(-0) == 0)\nprint(operator.unm(-1))\n--[[test\n-1\ntrue\ntrue\n1\n--test]]\n\nprint(operator.pow(2, 3))\nprint(operator.pow(0, 10))\nprint(operator.pow(2, 0))\n--[[test\n8\n0\n1\n--test]]\n\nprint(operator.sub(2, 3))\nprint(operator.sub(0, 10))\nprint(operator.sub(2, 2))\n--[[test\n-1\n-10\n0\n--test]]\n\n--------------------------------------------------------------------------------\n-- String operators\n--------------------------------------------------------------------------------\n\nprint(operator.concat(\"aa\", \"bb\"))\nprint(operator.concat(\"aa\", \"\"))\nprint(operator.concat(\"\", \"bb\"))\n--[[test\naabb\naa\nbb\n--test]]\n\nprint(operator.len(\"\"))\nprint(operator.len(\"ab\"))\nprint(operator.len(\"abcd\"))\n--[[test\n0\n2\n4\n--test]]\n\nprint(operator.length(\"\"))\nprint(operator.length(\"ab\"))\nprint(operator.length(\"abcd\"))\n--[[test\n0\n2\n4\n--test]]\n\n----------------------------------------------------------------------------\n-- Logical operators\n----------------------------------------------------------------------------\n\nprint(operator.land(true, true))\nprint(operator.land(true, false))\nprint(operator.land(false, true))\nprint(operator.land(false, false))\nprint(operator.land(1, 0))\nprint(operator.land(0, 1))\nprint(operator.land(1, 1))\nprint(operator.land(0, 0))\n--[[test\ntrue\nfalse\nfalse\nfalse\n0\n1\n1\n0\n--test]]\n\nprint(operator.lor(true, true))\nprint(operator.lor(true, false))\nprint(operator.lor(false, true))\nprint(operator.lor(false, false))\nprint(operator.lor(1, 0))\nprint(operator.lor(0, 1))\nprint(operator.lor(1, 1))\nprint(operator.lor(0, 0))\n--[[test\ntrue\ntrue\ntrue\nfalse\n1\n0\n1\n0\n--test]]\n\nprint(operator.lnot(true))\nprint(operator.lnot(false))\nprint(operator.lor(1))\nprint(operator.lor(0))\n--[[test\nfalse\ntrue\n1\n0\n--test]]\n\nprint(operator.truth(true))\nprint(operator.truth(false))\nprint(operator.truth(1))\nprint(operator.truth(0))\nprint(operator.truth(nil))\nprint(operator.truth(\"\"))\nprint(operator.truth({}))\n--[[test\ntrue\nfalse\ntrue\ntrue\nfalse\ntrue\ntrue\n--test]]\n"
  },
  {
    "path": "tests/reducing.lua",
    "content": "--------------------------------------------------------------------------------\n-- foldl\n--------------------------------------------------------------------------------\n\nprint(foldl(function(acc, x) return acc + x end, 0, range(5)))\n--[[test\n15\n--test]]\n\nprint(foldl(operator.add, 0, range(5)))\n--[[test\n15\n--test]]\n\nprint(foldl(function(acc, x, y) return acc + x * y; end, 0,\n    zip(range(1, 5), {4, 3, 2, 1})))\n--[[test\n20\n--test]]\n\nprint(reduce == foldl) -- an alias\n--[[test\ntrue\n--test]]\n\n--------------------------------------------------------------------------------\n-- length\n--------------------------------------------------------------------------------\n\nprint(length({\"a\", \"b\", \"c\", \"d\", \"e\"}))\n--[[test\n5\n--test]]\n\nprint(length({}))\n--[[test\n0\n--test]]\n\nprint(length(range(0)))\n--[[test\n0\n--test]]\n\n-- gh-55: consider input iterator state in array/string optimizations\nprint(length(drop_n(3, {\"a\", \"b\", \"c\", \"d\", \"e\"})))\n--[[test\n2\n--test]]\n\n-- gh-55: consider input iterator state in array/string optimizations\nprint(length(drop_n(3, \"abcdef\")))\n--[[test\n3\n--test]]\n\n\n--------------------------------------------------------------------------------\n-- is_null\n--------------------------------------------------------------------------------\n\nprint(is_null({\"a\", \"b\", \"c\", \"d\", \"e\"}))\n--[[test\nfalse\n--test]]\n\nprint(is_null({}))\n--[[test\ntrue\n--test]]\n\nprint(is_null(range(0)))\n--[[test\ntrue\n--test]]\n\nlocal gen, init, state = range(5)\nprint(is_null(gen, init, state))\ndump(gen, init, state)\n--[[test\nfalse\n1\n2\n3\n4\n5\n--test]]\n\n--------------------------------------------------------------------------------\n-- is_prefix_of\n--------------------------------------------------------------------------------\n\nprint(is_prefix_of({\"a\"}, {\"a\", \"b\", \"c\"}))\n--[[test\ntrue\n--test]]\n\nprint(is_prefix_of({}, {\"a\", \"b\", \"c\"}))\n--[[test\ntrue\n--test]]\n\nprint(is_prefix_of({}, {}))\n--[[test\ntrue\n--test]]\n\nprint(is_prefix_of({\"a\"}, {}))\n--[[test\nfalse\n--test]]\n\nprint(is_prefix_of({\"a\"}, {\"b\"}))\n--[[test\nfalse\n--test]]\n\nprint(is_prefix_of({\"a\", \"b\"}, {\"a\", \"c\"}))\n--[[test\nfalse\n--test]]\n\nprint(is_prefix_of({\"a\", \"b\", \"c\"}, {\"a\", \"b\"}))\n--[[test\nfalse\n--test]]\n\nprint(is_prefix_of(range(5), range(6)))\n--[[test\ntrue\n--test]]\n\nprint(is_prefix_of(range(6), range(5)))\n--[[test\nfalse\n--test]]\n\nprint(is_prefix_of(range(15), range(15)))\n--[[test\ntrue\n--test]]\n\nprint(is_prefix_of(range(21), range(20)))\n--[[test\nfalse\n--test]]\n\nprint(is_prefix_of(range(15), range(20)))\n--[[test\ntrue\n--test]]\n\nprint(is_prefix_of(\n    range(3):map(function(v) return v < 3 and v or nil end), -- {1, 2, nil}\n    { 1, 2 }\n))\n--[[test\nfalse\n--test]]\n\nlocal function range_once(stop)\n    local v = 0\n    return function()\n        v = v + 1\n        if v <= stop then\n            return v, v\n        end\n\n        return nil\n    end\nend\n\nlocal prefix = range_once(2) -- null expected\nlocal iterator = range_once(3) -- trimmed prefix expected\n\nprint(is_prefix_of(wrap(prefix), wrap(iterator)))\nprint(is_null(prefix))\nprint((iterator()))\n--[[test\ntrue\ntrue\n3\n--test]]\n\n--------------------------------------------------------------------------------\n-- all\n--------------------------------------------------------------------------------\n\nprint(all(function(x) return x end, {true, true, true, true}))\n--[[test\ntrue\n--test]]\n\nprint(all(function(x) return x end, {true, true, true, false}))\n--[[test\nfalse\n--test]]\n\nprint(all(function(x) return x end, {}))\n--[[test\ntrue\n--test]]\n\nprint(every == all) -- an alias\n--[[test\ntrue\n--test]]\n\n--------------------------------------------------------------------------------\n-- any\n--------------------------------------------------------------------------------\n\nprint(any(function(x) return x end, {false, false, false, false}))\n--[[test\nfalse\n--test]]\n\nprint(any(function(x) return x end, {false, false, false, true}))\n--[[test\ntrue\n--test]]\n\nprint(any(function(x) return x end, {}))\n--[[test\nfalse\n--test]]\n\nprint(some == any) -- an alias\n--[[test\ntrue\n--test]]\n\n--------------------------------------------------------------------------------\n-- sum\n--------------------------------------------------------------------------------\n\nprint(sum(range(1, 5)))\n--[[test\n15\n--test]]\n\nprint(sum(range(1, 5, 0.5)))\n--[[test\n27\n--test]]\n\nprint(sum(range(0)))\n--[[test\n0\n--test]]\n\n--------------------------------------------------------------------------------\n-- product\n--------------------------------------------------------------------------------\n\nprint(product(range(1, 5)))\n--[[test\n120\n--test]]\n\nprint(product(range(1, 5, 0.5)))\n--[[test\n7087.5\n--test]]\n\nprint(product(range(0)))\n--[[test\n1\n--test]]\n\n\n--------------------------------------------------------------------------------\n-- min\n--------------------------------------------------------------------------------\n\nprint(min(range(1, 10, 1)))\n--[[test\n1\n--test]]\n\nprint(min({\"f\", \"d\", \"c\", \"d\", \"e\"}))\n--[[test\nc\n--test]]\n\nprint(min({}))\n--[[test\nerror: min: iterator is empty\n--test]]\n\nprint(minimum == min) -- an alias\n--[[test\ntrue\n--test]]\n\n--------------------------------------------------------------------------------\n-- min_by\n--------------------------------------------------------------------------------\n\nfunction min_cmp(a, b) if -a < -b then return a else return b end end\n--[[test\n--test]]\n\nprint(min_by(min_cmp, range(1, 10, 1)))\n--[[test\n10\n--test]]\n\nprint(min_by(min_cmp, {}))\n--[[test\nerror: min: iterator is empty\n--test]]\n\nprint(minimum_by == min_by) -- an alias\n--[[test\ntrue\n--test]]\n\n--------------------------------------------------------------------------------\n-- max\n--------------------------------------------------------------------------------\n\nprint(max(range(1, 10, 1)))\n--[[test\n10\n--test]]\n\nprint(max({\"f\", \"d\", \"c\", \"d\", \"e\"}))\n--[[test\nf\n--test]]\n\nprint(max({}))\n--[[test\nerror: max: iterator is empty\n--test]]\n\nprint(maximum == max) -- an alias\n--[[test\ntrue\n--test]]\n\n--------------------------------------------------------------------------------\n-- max_by\n--------------------------------------------------------------------------------\n\nfunction max_cmp(a, b) if -a > -b then return a else return b end end\n--[[test\n--test]]\n\nprint(max_by(max_cmp, range(1, 10, 1)))\n--[[test\n1\n--test]]\n\nprint(max_by(max_cmp, {}))\n--[[test\nerror: max: iterator is empty\n--test]]\n\nprint(maximum_by == max_by) -- an alias\n--[[test\ntrue\n--test]]\n"
  },
  {
    "path": "tests/runtest",
    "content": "#!/usr/bin/env lua\n\npackage.path = \"../?.lua;\"..package.path\nrequire \"fun\" ()\nfunction dump(gen, init, state) each(print, gen, init, state) end\n\n-- Check if state is preserved\nfunction dump_state(gen, init, state)\n    for s in gen, init, state do\n        print(s)\n    end\nend\n\nlocal unpack = rawget(table, \"unpack\") or unpack\nlocal loadstring = rawget(_G, \"loadstring\") or load\n\nfunction file_print(file, ...)\n    local n, i = select(\"#\",...)\n    for i=1,n do\n        local x = select(i, ...)\n        if type(x) == \"number\" and math.floor(x) == math.ceil(x) then\n            -- A special hack for Lua 5.3: remove .0 for integer\n            x = string.match(select(i,...), '^-?%d+')\n        end\n        file:write(tostring(x))\n        if i~=n then\n            file:write(' ')\n        end\n    end\n    file:write('\\n')\nend\n\nlocal globals = {}\nsetmetatable(_G, {\n    __newindex = function(t,k,v)\n        local info = debug.getinfo(2, \"S\")\n        if info.short_src:sub(1,7) ~= '[string' then\n            local file = info.short_src\n            local func = debug.getinfo(2, \"n\").name or \"\"\n            local line = info.linedefined\n            globals[file..':'..line..':'..k] = {file, line, func, k}\n        end\n        rawset(t, k, v)\n    end\n})\n\nlocal function process(test_name)\n    io.write(\"Testing \", test_name, \"\\n\")\n    local new_name = test_name..\".new\"\n    local test_file = io.open(test_name, 'r')\n    local content = test_file:read(\"*a\");\n    test_file:close()\n\n    local new_file = io.open(new_name, 'w')\n\n    local prev_print = print\n    print = function(...) file_print(new_file, ...) end\n\n    io.flush()\n    local expr\n    for expr in content:gmatch(\"(.-)%s*--%[%[test.-test%]%]\") do\n        new_file:write(expr)\n        new_file:write(\"\\n--[[test\\n\")\n        local res, err = loadstring(expr)\n        if res then\n            res, err = pcall(res, expr)\n        end\n        if not res then\n            new_file:write('error: ', err:match(\".-:%d+:%s*(.*)\"), \"\\n\")\n        end\n        new_file:write(\"--test]]\")\n    end\n    new_file:write(\"\\n\")\n    new_file:close()\n\n    print = prev_print\n\n    local r = os.execute(string.format('diff -U4 \"%s\" \"%s\" 2>&1',\n        test_name, new_name))\n    if r then\n        os.remove(new_name)\n        return true\n    else\n        return false\n    end\nend\n\nif #arg <= 0 then\n    io.write(\"Usage: runtest *.lua\", \"\\n\")\n    os.exit(1)\nend\n\nlocal failed, i = {}\nfor i=1,#arg,1 do\n    local test_name = arg[i]\n    if not process(test_name) then\n        table.insert(failed, test_name)\n    end\nend\n\nif #failed > 0 then\n    io.write(\"\\n\")\n    io.write(\"Failed tests:\", \"\\n\")\n    for _k,test_name in ipairs(failed) do\n        io.write(\"   \", test_name, \"\\n\")\n    end\n    io.write(\"\\n\", \"Please review *.new files and update tests\", \"\\n\")\nend\n\nif next(globals) then\n    io.write(\"\\n\")\n    io.write(\"Some global variables have been declared by mistake:\", \"\\n\")\n    for k, pollution in pairs(globals) do\n        local file, line, func, var = unpack(pollution)\n        io.write(file..\":\"..line..\" function \"..func..\"() = var '\"..var..\"'\", \"\\n\")\n    end\n    io.write(\"\\n\", \"Please declare them with the local statement\", \"\\n\")\nelseif #failed == 0 then\n    io.write(\"All tests have passed!\", \"\\n\")\n    os.exit(0)\nend\n"
  },
  {
    "path": "tests/slicing.lua",
    "content": "--------------------------------------------------------------------------------\n-- nth\n--------------------------------------------------------------------------------\n\nprint(nth(2, range(5)))\n--[[test\n2\n--test]]\n\nprint(nth(10, range(5)))\n--[[test\nnil\n--test]]\n\nprint(nth(2, range(0)))\n--[[test\nnil\n--test]]\n\nprint(nth(2, {\"a\", \"b\", \"c\", \"d\", \"e\"}))\n--[[test\nb\n--test]]\n\nprint(nth(2, enumerate({\"a\", \"b\", \"c\", \"d\", \"e\"})))\n--[[test\n2 b\n--test]]\n\nprint(nth(1, \"abcdef\"))\n--[[test\na\n--test]]\n\nprint(nth(2, \"abcdef\"))\n--[[test\nb\n--test]]\n\nprint(nth(6, \"abcdef\"))\n--[[test\nf\n--test]]\n\nprint(nth(0, \"abcdef\"))\n--[[test\nerror: invalid first argument to nth\n--test]]\n\nprint(nth(7, \"abcdef\"))\n--[[test\nnil\n--test]]\n\n-- gh-55: consider input iterator state in array/string optimizations\nprint(nth(1, drop_n(3, {\"a\", \"b\", \"c\", \"d\", \"e\"})))\n--[[test\nd\n--test]]\n\n-- gh-55: consider input iterator state in array/string optimizations\nprint(nth(1, drop_n(3, \"abcdef\")))\n--[[test\nd\n--test]]\n\n--------------------------------------------------------------------------------\n-- head\n--------------------------------------------------------------------------------\n\nprint(head({\"a\", \"b\", \"c\", \"d\", \"e\"}))\n--[[test\na\n--test]]\n\nprint(head({}))\n--[[test\nerror: head: iterator is empty\n--test]]\n\nprint(head(range(0)))\n--[[test\nerror: head: iterator is empty\n--test]]\n\nprint(head(enumerate({\"a\", \"b\"})))\n--[[test\n1 a\n--test]]\n\nprint(car == head) -- an alias\n--[[test\ntrue\n--test]]\n\n--------------------------------------------------------------------------------\n-- tail\n--------------------------------------------------------------------------------\n\ndump(tail({\"a\", \"b\", \"c\", \"d\", \"e\"}))\n--[[test\nb\nc\nd\ne\n--test]]\n\ndump(tail({}))\n--[[test\n--test]]\n\ndump(tail(range(0)))\n--[[test\n--test]]\n\ndump(tail(enumerate({\"a\", \"b\"})))\n--[[test\n2 b\n--test]]\n\nprint(cdr == tail) -- an alias\n--[[test\ntrue\n--test]]\n\ndump_state(tail(ipairs({\"a\", \"b\", \"c\", \"d\", \"e\"})))\n--[[test\n2\n3\n4\n5\n--test]]\n\n\n--------------------------------------------------------------------------------\n-- take_n\n--------------------------------------------------------------------------------\n\ndump(take_n(0, duplicate(48)))\n--[[test\n--test]]\n\ndump(take_n(5, range(0)))\n--[[test\n--test]]\n\ndump(take_n(1, duplicate(48)))\n--[[test\n48\n--test]]\n\ndump(take_n(5, duplicate(48)))\n--[[test\n48\n48\n48\n48\n48\n--test]]\n\ndump(take_n(5, enumerate(duplicate('x'))))\n--[[test\n1 x\n2 x\n3 x\n4 x\n5 x\n--test]]\n\n--------------------------------------------------------------------------------\n-- take_while\n--------------------------------------------------------------------------------\n\ndump(take_while(function(x) return x < 5 end, range(10)))\n--[[test\n1\n2\n3\n4\n--test]]\n\ndump(take_while(function(x) return x < 5 end, range(0)))\n--[[test\n--test]]\n\ndump(take_while(function(x) return x > 100 end, range(10)))\n--[[test\n--test]]\n\ndump(take_while(function(i, a) return i ~=a end, enumerate({5, 2, 1, 3, 4})))\n--[[test\n1 5\n--test]]\n\ndump_state(take_while(function(x) return x < 3 end, ipairs({0, 0, 0, 2, 3})))\n--[[test\n1\n2\n3\n4\n--test]]\n\n--------------------------------------------------------------------------------\n-- take\n--------------------------------------------------------------------------------\n\ndump(take(function(x) return x < 5 end, range(10)))\n--[[test\n1\n2\n3\n4\n--test]]\n\ndump(take(5, duplicate(48)))\n--[[test\n48\n48\n48\n48\n48\n--test]]\n\n--------------------------------------------------------------------------------\n-- drop_n\n--------------------------------------------------------------------------------\n\ndump(drop_n(5, range(10)))\n--[[test\n6\n7\n8\n9\n10\n--test]]\n\ndump(drop_n(0, range(5)))\n--[[test\n1\n2\n3\n4\n5\n--test]]\n\ndump(drop_n(5, range(0)))\n--[[test\n--test]]\n\ndump(drop_n(2, enumerate({'a', 'b', 'c', 'd', 'e'})))\n--[[test\n3 c\n4 d\n5 e\n--test]]\n\ndump_state(drop_n(3, ipairs({'a', 'b', 'c', 'd', 'e'})))\n--[[test\n4\n5\n--test]]\n\n--------------------------------------------------------------------------------\n-- drop_while\n--------------------------------------------------------------------------------\n\ndump(drop_while(function(x) return x < 5 end, range(10)))\n--[[test\n5\n6\n7\n8\n9\n10\n--test]]\n\ndump(drop_while(function(x) return x < 5 end, range(0)))\n--[[test\n--test]]\n\ndump(drop_while(function(x) return x > 100 end, range(10)))\n--[[test\n1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n--test]]\n\ndump(drop_while(function(i, a) return i ~=a end, enumerate({5, 2, 1, 3, 4})))\n--[[test\n2 2\n3 1\n4 3\n5 4\n--test]]\n\ndump(drop_while(function(i, a) return i ~=a end,\n    zip({1, 2, 3, 4, 5}, {5, 4, 3, 2, 1})))\n--[[test\n3 3\n4 2\n5 1\n--test]]\n\ndump_state(drop_while(function(x) return x < 5 end, ipairs({0, 0, 4, 6, 2})))\n--[[test\n4\n5\n--test]]\n\n--------------------------------------------------------------------------------\n-- drop\n--------------------------------------------------------------------------------\n\ndump(drop(5, range(10)))\n--[[test\n6\n7\n8\n9\n10\n--test]]\n\ndump(drop(function(x) return x < 5 end, range(10)))\n--[[test\n5\n6\n7\n8\n9\n10\n--test]]\n\n\n--------------------------------------------------------------------------------\n-- span\n--------------------------------------------------------------------------------\n\ndump(zip(span(function(x) return x < 5 end, range(10))))\n--[[test\n1 5\n2 6\n3 7\n4 8\n--test]]\n\ndump(zip(span(5, range(10))))\n--[[test\n1 6\n2 7\n3 8\n4 9\n5 10\n--test]]\n\ndump(zip(span(function(x) return x < 5 end, range(0))))\n--[[test\n--test]]\n\ndump(zip(span(function(x) return x < 5 end, range(5))))\n--[[test\n1 5\n--test]]\n\nprint(split == span) -- an alias\n--[[test\ntrue\n--test]]\n\nprint(split_at == span) -- an alias\n--[[test\ntrue\n--test]]\n"
  },
  {
    "path": "tests/stateful.lua",
    "content": "-- compatibility with Lua 5.1/5.2\nlocal unpack = rawget(table, \"unpack\") or unpack\n\nfunction gen_stateful_iter(values)\n    local i = 1\n    local gen = function(_param, values)\n        if i > #values then\n            return nil\n        end\n        local t = values[i]\n        i = i + 1\n        if type(t) == 'table' then\n            return values, unpack(t, 1, table.maxn(t))\n        else\n            return values, t\n        end\n    end\n    return iter(gen, nil, values)\nend\n\n--------------------------------------------------------------------------------\n-- drop_while\n--------------------------------------------------------------------------------\n\n-- Simple test\ndump(gen_stateful_iter({1, 2, 3, 4, 5, 6, 5, 4, 3}):drop_while(function(x) return x < 5 end))\n--[[test\n5\n6\n5\n4\n3\n--test]]\n\n-- Multireturn\ndump(gen_stateful_iter({{1, 10}, {3, 30}, {5, 50}, {6, 60}, {3, 20}}):drop_while(function(x) return x < 5 end))\n--[[test\n5 50\n6 60\n3 20\n--test]]\n\n-- Multireturn with nil\ndump(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))\n--[[test\n5 nil 50\n6 nil 60\n3 nil 20\n--test]]\n\n-- Multireturn with condition on second returned value\ndump(gen_stateful_iter({{0, 1}, {0, 3}, {0, 5}, {0, 4}}):drop_while(function(x, y) return y < 5 end))\n--[[test\n0 5\n0 4\n--test]]\n\n-- Empty iterator\ndump(gen_stateful_iter({}):drop_while(function(x) return x < 5 end))\n--[[test\n--test]]\n\n-- Always false\ndump(gen_stateful_iter({1, 2, 3, 4, 5}):drop_while(function(x) return x > 100 end))\n--[[test\n1\n2\n3\n4\n5\n--test]]\n"
  },
  {
    "path": "tests/transformations.lua",
    "content": "--------------------------------------------------------------------------------\n-- map\n--------------------------------------------------------------------------------\n\nfun = function(...) return 'map', ... end\n\ndump(map(fun, range(0)))\n--[[test\n--test]]\n\n\ndump(map(fun, range(4)))\n--[[test\nmap 1\nmap 2\nmap 3\nmap 4\n--test]]\n\ndump(map(fun, enumerate({\"a\", \"b\", \"c\", \"d\", \"e\"})))\n--[[test\nmap 1 a\nmap 2 b\nmap 3 c\nmap 4 d\nmap 5 e\n--test]]\n\ndump(map(function(x) return 2 * x end, range(4)))\n--[[test\n2\n4\n6\n8\n--test]]\n\nfun = nil\n--[[test\n--test]]\n\n--------------------------------------------------------------------------------\n-- enumerate\n--------------------------------------------------------------------------------\n\ndump(enumerate({\"a\", \"b\", \"c\", \"d\", \"e\"}))\n--[[test\n1 a\n2 b\n3 c\n4 d\n5 e\n--test]]\n\ndump(enumerate(enumerate(enumerate({\"a\", \"b\", \"c\", \"d\", \"e\"}))))\n--[[test\n1 1 1 a\n2 2 2 b\n3 3 3 c\n4 4 4 d\n5 5 5 e\n--test]]\n\ndump(enumerate(zip({\"one\", \"two\", \"three\", \"four\", \"five\"},\n    {\"a\", \"b\", \"c\", \"d\", \"e\"})))\n--[[test\n1 one a\n2 two b\n3 three c\n4 four d\n5 five e\n--test]]\n\n--------------------------------------------------------------------------------\n-- intersperse\n--------------------------------------------------------------------------------\n\ndump(intersperse(\"x\", {}))\n\ndump(intersperse(\"x\", {\"a\", \"b\", \"c\", \"d\", \"e\"}))\n--[[test\na\nx\nb\nx\nc\nx\nd\nx\ne\nx\n--test]]\n\ndump(intersperse(\"x\", {\"a\", \"b\", \"c\", \"d\", \"e\", \"f\"}))\n--[[test\na\nx\nb\nx\nc\nx\nd\nx\ne\nx\nf\nx\n--test]]\n"
  }
]