# Lua Fun: functional programming for Lua built around LuaJIT's trace compiler

> Lua Fun gives Lua developers over 50 functional primitives including map, filter, reduce and zip, and is designed so that LuaJIT's trace compiler can turn nested functional expressions into tight machine loops. Its master branch carries an early alpha designation; a separate stable branch exists for production.

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

- Repository: https://github.com/luafun/luafun
- Website: https://luafun.github.io/
- Stars: 2,266 · Forks: 113
- Language: Lua
- License: NOASSERTION
- Published: 2026-10-11 · Updated: 2026-10-11 · Language: en
- Canonical page: https://hysenlabs.com/projects/luafun-luafun

## Over 50 functional primitives for Lua, designed around LuaJIT's trace compiler

Lua developers who want a functional style face a practical problem: a naive implementation of map, filter and reduce carries a function-call overhead on every iteration. Lua Fun addresses this by designing each primitive to be transparent to LuaJIT's trace compiler, so the compiler can inline and merge them into a single compiled loop rather than executing them as a sequence of calls.

Over 50 primitives are provided, including the higher-order functions a programmer familiar with Standard ML, Haskell, Erlang, JavaScript or Python would expect. map, filter, reduce and zip are named explicitly in the project description; the full set is documented at luafun.github.io.

All of this fits in a single file, fun.lua, at the repository root. That design choice has a practical side effect: the complete implementation is auditable by reading one file, and adding the library to a project requires nothing more than copying that file.

## 2 calling styles for the same set of primitives: global injection and method chaining

2 calling styles are available. With the functional style, a single call injects all primitives into the global environment:

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

After require "fun" (), names like reduce, map and range are globally available. With the object-oriented style, everything goes through a local table and chains off prior results:

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

Both calls produce 328350 for the same input. Global injection is terser for interactive use and scripts where naming collisions are not a concern. Method chaining avoids polluting the global namespace, which matters more in a larger codebase where another module might already define a name like map.

## Installing via LuaRocks using fun-scm-1.rockspec or copying fun.lua directly

2 installation paths exist. LuaRocks is the package manager the project targets, and a RockSpec file named fun-scm-1.rockspec is at the repository root. No explicit luarocks install command appears in the repository documentation; the project links the rockspec file directly for download.

Copying fun.lua into a project directory is the other path. Since the whole library is that 1 file, dropping it in and requiring it works without a build step or dependency resolution. This path is particularly useful for projects that do not use LuaRocks or that vendor their dependencies.

Setup details beyond the README are at luafun.github.io/getting_started.html. That page covers the initial steps for new users, and the repository's HACKING.md covers development setup for anyone who wants to modify the library itself.

## LuaJIT traces a functional chain to one machine loop in native code

Running luajit -jdump on the example above shows what LuaJIT does with the chain at runtime:

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

The project describes this as "one machine loop containing just 10 CPU assembly instructions without CALL." Counting the lines inside the ->LOOP block gives 9 instructions, not 10. Whether that discrepancy is a typo or reflects an instruction the dump notation elides is not explained in the project.

The practical point is that the range, map and reduce calls were merged by the trace compiler into a single compiled loop with no function-call dispatch visible. That is the core architectural claim: high-order functions that a naive implementation would execute as nested calls become a flat loop under LuaJIT.

## The master branch carries an early alpha designation and an unstable API

Master is the development branch, designated early alpha. 2 things follow from that. First, the API is not frozen: function signatures, calling conventions and primitive names can change between commits without any formal announcement. Second, a stable branch exists and is the project's own recommendation for production deployments.

For anyone who continues using master, the documented mechanism for tracking breaking changes is to grep git log for the string "Incompatible API changes". No formal record of breaking changes is maintained outside that git log, so that grep is the only structured way to spot a breaking commit.

This is an unusual maintenance model. Most production dependencies have a documented breaking-changes mechanism or a semantic versioning contract. Lua Fun's answer is a branch pair, stable and master, with the expectation that production users stay on stable and take responsibility for monitoring master themselves.

## LuaJIT 2.1 alpha is the recommended runtime and Lua 5.1-5.3 are also supported

LuaJIT 2.1 alpha is the recommended runtime for Lua Fun. That recommendation appears without qualification: 2.1 alpha is treated as the expected production LuaJIT version, not a caveat. The trace compiler behaviors the library relies on, including tail-call tracing, up-recursion and down-recursion handling, are documented on the LuaJIT wiki pages linked from the project.

Lua 5.1-5.3 are also supported for users who are not running LuaJIT. On those versions, the library still works as a functional-primitives collection, but the JIT compilation that produces the tight native loop output shown in the dump section does not apply.

Nothing in the project documentation covers compatibility with Lua runtimes beyond the 5.1-5.3 range, so users on other Lua versions should test before committing to the library.

## Written for Tarantool and distributed without numbered Git tags

Lua Fun was originally written to use with Tarantool, an in-memory data store and Lua application server described in the project as "an efficient in-memory store and an asynchronous Lua application server." That origin explains the performance focus: Tarantool runs Lua for application logic inside a server process, and a functional library that compiles to native code fits the latency requirements of that architecture. Lua Fun is general enough to use outside Tarantool, but its design priorities came from that context.

GitHub carries no tagged releases for this project. The rockspec filename fun-scm-1.rockspec uses the SCM convention, indicating distribution from source control rather than numbered artifacts. Pinning to a specific version means tracking a specific commit hash or keeping a local copy of fun.lua.

Lua Fun is distributed under the MIT/X11 License, the same terms as Lua and LuaJIT. GitHub classifies it as Other because the text lives in COPYING.md rather than a standard-named file.

## Conclusion

Lua Fun is worth evaluating for LuaJIT projects that want map, filter, reduce and related primitives without paying a per-call function overhead. Skip it if you need a frozen API, a documented support story for Lua beyond 5.3, or a numbered artifact to pin: none of those are present. Before adopting, checkout the stable branch rather than master, read the Getting Started guide at luafun.github.io/getting_started.html, and run luajit -jdump on your own code to verify the trace compiler is actually merging the chains you care about.

## FAQ

### What is Lua Fun?

Lua Fun is a functional programming library for Lua that provides over 50 primitives such as map, filter, reduce and zip. It is designed for LuaJIT's trace compiler so that functional chains compile to tight native machine loops rather than executing as nested function calls.

### How do I install Lua Fun?

Copy fun.lua from the repository into your project, or use LuaRocks with the fun-scm-1.rockspec file at the repository root. Getting Started documentation is at luafun.github.io/getting_started.html.

### Is Lua Fun safe to use in production?

The master branch carries an early alpha designation and an unstable API. The project's own recommendation is to use the stable branch for production deployments.

### Does Lua Fun require LuaJIT?

LuaJIT 2.1 alpha is recommended, and the native-loop compilation only occurs under LuaJIT. Lua 5.1-5.3 are also supported, but on those runtimes the library functions as a standard functional-primitives collection without JIT compilation.

### Is Lua Fun still maintained?

The repository is not archived and the last push was on 2026-09-21. No tagged releases exist on GitHub; the stable and master branches are the 2 access points.

## Sources

- [Issues](https://github.com/luafun/luafun/issues)
- [luafun/luafun on GitHub](https://github.com/luafun/luafun)
- [Project website](https://luafun.github.io/)
- [README](https://github.com/luafun/luafun/blob/master/README.md)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/luafun-luafun
