{"id":16788593,"url":"https://github.com/mna/luafn","last_synced_at":"2025-07-23T23:09:05.129Z","repository":{"id":145701734,"uuid":"281261626","full_name":"mna/luafn","owner":"mna","description":"Functional programming fundamentals for Lua. (mirror)","archived":false,"fork":false,"pushed_at":"2022-07-05T20:35:59.000Z","size":26,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-03-17T00:41:29.683Z","etag":null,"topics":["functional-programming","lua","mirror"],"latest_commit_sha":null,"homepage":"","language":"Lua","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mna.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-07-21T01:10:56.000Z","updated_at":"2022-07-05T20:28:12.000Z","dependencies_parsed_at":"2023-04-07T23:47:31.977Z","dependency_job_id":null,"html_url":"https://github.com/mna/luafn","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/mna/luafn","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mna%2Fluafn","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mna%2Fluafn/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mna%2Fluafn/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mna%2Fluafn/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mna","download_url":"https://codeload.github.com/mna/luafn/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mna%2Fluafn/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":266765383,"owners_count":23980761,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-23T02:00:09.312Z","response_time":66,"last_error":null,"robots_txt_status":null,"robots_txt_updated_at":null,"robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["functional-programming","lua","mirror"],"created_at":"2024-10-13T08:18:23.368Z","updated_at":"2025-07-23T23:09:05.124Z","avatar_url":"https://github.com/mna.png","language":"Lua","readme":"# luafn\n\nA pure Lua module with no external dependency that provides functional programming fundamentals such as map, filter, reduce and pipe. All core functions work with iterators and as such are lazily evaluated.\n\n* Canonical repository: https://git.sr.ht/~mna/luafn\n* Issue tracker: https://todo.sr.ht/~mna/luafn\n\n## Install\n\nVia Luarocks:\n\n```\n$ luarocks install luafn\n```\n\nOr simply copy the single fn.lua file in your project or your `LUA_PATH`.\n\n## API\n\nAssuming `local fn = require 'fn'`. You can check out the tests, and especially `tests/usecases.lua` for actual examples of using the API.\n\n### `fn.fromto(from, to)`\n\nReturn an iterator that generates all integers starting at from\nand ending at to, inclusive.\n\n### `fn.partial(f, ...)`\n\nPartial binds the provided arguments to function f and returns a new\nfunction that, when called, executes with the combination of the\npartially-applied arguments and newly provided arguments.\n\n### `fn.partialtrail(f, exactly, ...)`\n\nSame as partial, except that the partially-applied arguments are added\nat the end of the newly provided arguments. If exactly is not nil, then\nthat exact number of newly provided arguments are passed before adding\nthe partially-applied ones, adding nil values in-between as required.\n\n### `fn.pipe(...)`\n\nPipe returned values to the input arguments of the next function,\nin left-to-right composition.\nReturn a function that applies the pipe.\n\n### `fn.filter(p, it, inv, ctl)`\n\nFilter iterator it by keeping only items that satisfy predicate p.\nReturn a new iterator that applies the filter.\nIf \"it\" is nil, returns a partially-applied function with the predicate\nset.\n\n### `fn.map(f, it, inv, ctl)`\n\nMap iterator it by calling f on each iteration and returning its\nreturned values instead of the original ones. Note that returning\nnil from f as first value end the iterator.\nReturn a new iterator that applies the map.\nIf \"it\" is nil, returns a partially-applied function with the map\nfunction set.\n\n### `fn.reduce(f, cumul, it, inv, ctl)`\n\nReduce iterator it by calling fn on each iteration with the\naccumulator cumul and all values returned for this iteration.\nReturn the final value of the accumulator.\nIf \"it\" is nil, returns a partially-applied function with the\nreduce function and, if provided, the accumulator value.\n\n### `fn.taken(n, it, inv, ctl)`\n\nTake the first n results of iterator it.\nReturn a new iterator that takes at most those first n results.\nIf \"it\" is nil, returns a partially-applied function with the n\nvalue set.\n\n### `fn.takewhile(p, it, inv, ctl)`\n\nTake the iterator's it results while the predicate p returns true.\nThe predicate is called with the values of each iteration.\nReturn a new iterator that applies the take while condition.\nIf \"it\" is nil, returns a partially-applied function with the predicate\np set.\n\n### `fn.skipn(n, it, inv, ctl)`\n\nSkip the first n results of iterator it.\nReturn a new iterator that skips those first n results.\nIf \"it\" is nil, returns a partially-applied function with the n\nvalue set.\n\n### `fn.skipwhile(p, it, inv, ctl)`\n\nSkip the iterator's it results while the predicate p returns true.\nThe predicate is called with the values of each iteration.\nReturn a new iterator that applies the skip while condition.\nIf \"it\" is nil, returns a partially-applied function with the predicate\np set.\n\n### `fn.any(p, it, inv, ctl)`\n\nAny calls predicate p with all values of each iteration of it and\nreturns true as soon as p returns true, along with the index of the\niteration that returned true and all its values.\nIt returns false as the only value if the iteration is completed\nwithout p returning true.\nIf \"it\" is nil, returns a partially-applied function with the predicate\np set.\n\n### `fn.all(p, it, inv, ctl)`\n\nAll calls predicate p with all values of each iteration of it and\nreturns false as soon as p returns false, along with the index of the\niteration that returned false and all its values.\nIt returns true as the only value if the iteration is completed without\np returning false.\nIf \"it\" is nil, returns a partially-applied function with the predicate\np set.\n\n### `fn.concat(...)`\n\nConcat concatenates the provided iterators together, returning\na new iterator that loops through all iterators in a single\nsequence. The arguments must be provided as a list of tables,\neach table an array containing the iterator tuple (i.e. the\niterator function, its invariant value and its control value).\nA common way to generate this is e.g.:\n  `fn.concat({pairs(t1)}, {pairs(t2)})`\nAnother option is with table.pack (the 'n' field is used if\nit is set):\n  `fn.concat(table.pack(pairs(t1)), table.pack(pairs(t2)))`\n\n### `fn.zip(...)`\n\nZip returns an iterator that returns the first value of all iterators at\neach iteration step. All iterators are iterated together at the same time,\nand iteration ends when the first iterator ends. If other iterators end\nearlier, the nil value is returned for this iterator.\n\nThe arguments must be provided as a list of tables, each table an array\ncontaining the iterator tuple (see documentation for concat for more\ndetails).\n\n### `fn.unzip(it, inv, ctl)`\n\nUnzip takes a single iterator and returns a new iterator that produces a\nsingle value on each iteration. The original iterator advances only when\nall its returned values for a given step have been returned as single-value\niteration steps. Note that any nil value in the values returned by the\noriginal iterator will stop the new iterator early, as nil are possible\nonly when not the first return value in a Lua iterator (otherwise they\nindicate the end of iteration).\n\n### `fn.select(n, it, inv, ctl)`\n\nSelect takes a single iterator and returns a new iterator that produces\nthe value(s) of the original iterator specified by n, which can be:\n    * A number, indicating the 1-based index of the value to select\n    * An array, indicating the 1-based indices of the values to select,\n      returned in the array's order.\n    * A function that will receive the original iterator's values and\n      return its returned values instead (same as map).\n\nIt is a specialized form of map. If \"it\" is nil, returns a partially-applied\nfunction with \"n\" set.\n\n### `fn.collectarray(t, it, inv, ctl)`\n\nCollects the first value of the iterator into an array, appending to t on\neach iteration. If t is nil, a new table is created. If \"it\" is nil, returns\na partially-applied function with \"t\" set. This function consumes the\niterator and returns t, it is a special case of reduce.\n\nTo collect multiple values from the iterator in an array, pipe from pack,\nselect or map.\n\n### `fn.collectkv(t, it, inv, ctl)`\n\nCollects the first two values of the iterator in a table, the first value\nbeing used as the key and the second as the value. If t is nil, a new table\nis created. If \"it\" is nil, returns a partially-applied function with \"t\"\nset. This function consumes the iterator and returns t, it is a special case\nof reduce.\n\nTo rearrange order of the iterator's values, see select.\n\n### `fn.pack(it, inv, ctl)`\n\nPacks takes an iterator and returns a new iterator that packs all values\nfrom the original iterator into an array and returns that array as iteration\nvalue instead. It is a specialized form of map.\n\n### `fn.callmethod(m, args, t, ...)`\n\nCallmethod calls the method m on table t, passing the args\nan any additional arguments received after t. The args\nparameter is treated as a \"packed\" table, it is unpacked when\nt.m is called, and the rest of the arguments (after t) are\npassed after the unpacked args. This is so that callmethod\ncan be partially applied with some arguments before receiving\nthe table instance on which to call the method.\nIf t is nil, returns a partially-applied function with the\nmethod name m and (if non-nil) the args table set. Pass an empty\ntable (and not nil) as args if there are no arguments to provide.\n\n## Development\n\nClone the project and install the required development dependencies:\n\n* luaunit (unit test runner)\n* luacov (recommended, test coverage)\n* luabenchmark (to run benchmarks)\n\nIf like me you prefer to keep your dependencies locally, per-project, then I recommend using my [llrocks] wrapper of the `luarocks` cli, which by default uses a local `lua_modules/` tree.\n\n```\n$ llrocks install ...\n```\n\nTo run tests and benchmarks:\n\n```\n$ llrocks run fn_test.lua\n$ llrocks run bench/*.lua\n```\n\nTo view code coverage:\n\n```\n$ llrocks cover fn_test.lua\n```\n\n## License\n\nThe [BSD 3-clause][bsd] license.\n\n[bsd]: http://opensource.org/licenses/BSD-3-Clause\n[llrocks]: https://git.sr.ht/~mna/llrocks\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmna%2Fluafn","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmna%2Fluafn","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmna%2Fluafn/lists"}