CLI tool
fogus/lemonad avatar
fogus/lemonad

lemonad: a Lisp-flavoured functional library for JavaScript

a functional programming library for javascript. an experiment in elegant JS.

659 stars29 forksJavaScriptMIT

At a glance

What is it?
lemonad is a small functional programming library for JavaScript, inspired by Clojure, Haskell, SML and Forth. It offers currying, a reference type with compare-and-swap, watchers, mixins and a pipeline, and it ships as a single file with an alpha version number and a very long todo list.
Who is it for?
Adopt lemonad if you want a compact functional core with currying, observable references and mixins in a single file, and if you are comfortable with a library whose API is still in an alpha line. It does not fit a project that needs a wide collection of array and object utilities, since the export list is roughly fifty names rather than a hundred and fifty, and it does not fit a codebase that needs type declarations, which the repository does not describe.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 86 days ago.
What is it written in?
Mainly JavaScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A small core with a Lisp-flavoured surface

The README opens with the lineage, and it is the most informative sentence in the file. lemonad is a functional programming library for JavaScript inspired by Clojure, Haskell, SML and Forth, and the project description calls it an experiment in elegant JavaScript. The influences list in the README is longer and more specific: Clojure and ClojureScript, Michael Bolin's patterns for inheritance in JavaScript, a general purpose JavaScript utility library, Oliver Steele's Functional JavaScript, and the book of the same name. That mix explains the shape of the API. The Clojure and Haskell references account for the currying and the Lisp-ish naming, the utility library accounts for the collection helpers, and the inheritance patterns paper accounts for the mixin mechanism, which is how the library extends objects with behaviour. The library is exposed as a single global object with a short name, L, which the test setup also exposes globally for the specs, and the export list is printed in the README as a single array of about fifty names. That is the whole public surface, and reading it is the fastest way to understand what the library is: a small, opinionated set of primitives rather than a utility grab bag.

What is actually in the export list

The list is worth grouping, because the categories are what you would use the library for. The currying family is the largest, with curry, curry2, curry3 and curry4, the reversed variants rcurry through rcurry4, partial1 and partial2, and a pipeline helper. Comparisons come next, with eq, gt, gte, lt and lte, and the type predicates with is, isArguments, isArray, isObject, isReference and isString. The collection functions are the familiar map, filter, reduce, nth, lift and invokeAll. The state part is the most distinctive, with a CAS constant and a CASMixin for compare and swap, a compareAndSwap function, a RefMixin, a Hole, a swap function, a setValue function, and the WatchableMixin together with addWatch and removeWatch for change notification. The rest is metaprogramming and plumbing: ctor and mix for construction, meth and invoker for invoking methods, typed, checker, dispatcher, actions, and one function whose name is a joke rather than a description, walterWhite. So the library is three things at once: a currying and comparison toolkit, a mutable reference with atomic style updates and watchers, and a small set of mixins for extending objects. If you only need the first, this is a heavier dependency than you want, and if you need the second, it is unusual enough to be worth the look.

Adding it to a project, and the version question

There is no command to run. The README's entire installation instruction is to add a line to the dependencies section of your package.json file.

json
    "lemonad": "0.7.4"

The version in that instruction is worth pausing on, because the package manifest in the repository declares 0.8.0-alpha.0. So the documented install target is the last stable line while the source tree is already on the next alpha. That is a normal way to develop a library, and it means you get a stable release from the registry while the repository holds the next iteration. It also means the API in the README's export list may or may not match what 0.7.4 actually exports, and the README does not document a changelog to check against, so the sensible move for a new user is to read the export list of the version you actually installed rather than the one in the readme file. The package is plain CommonJS, with the main entry point at ./lib/lemonad, and the engines field allows any Node version, so there is no runtime constraint to worry about. The licence is MIT, and the project homepage is functionaljs.org, with the author's own site listed in the manifest.

Jest, spec files and a global L for the tests

The development section of the README is short and modern, which is interesting for a library of this vintage. Setting up for development and installing the dev tools is a single command.

bash
npm install

That installs the production dependencies and the devDependencies, including Jest. Running the whole suite is npm test, and the test script in the manifest is jest, so the suite runs through the standard runner with no wrapper of your own. For the tighter loop, the README gives the two commands you actually use while writing code, a single spec file and watch mode.

bash
npx jest test/specs/<name>.spec.js
npx jest --watch

The notes under those commands explain one piece of setup that would otherwise confuse you. Spec files live under test/specs with a .spec.js suffix, and a setup file, test/jest.setup.js, exposes the library global L so that existing specs continue to work. That is a compatibility shim rather than a stylistic choice, and it tells you something about the library's history: the API was originally consumed as a global, and the test suite preserves that assumption so the older specs did not have to be rewritten when the module system was introduced. The repository root also carries a scripts directory, a docs directory and an examples directory, and the examples are named nationjs, poetry and proton, which are worked examples of the library applied to small problems rather than a general tutorial.

Documentation that is generated from the source, and checked

The documentation pipeline is more elaborate than a typical small library, and the interesting part is that it fails loudly. The docs script chains a clean step, an API step and an annotations step. The clean step removes the generated API page, the API markdown file and the annotations page along with their assets. The API step creates the output directory, generates markdown from the source with jsdoc2md, and then runs a check before generating the HTML, and the check is a small node script that reads the generated markdown and exits with an error if it is empty, printing a message about jsdoc2md finding no parseable JSDoc doclets. In other words, the build will not silently publish an empty API page if the doc comments stop being parseable, which is a cheap guard against a real failure mode in a library whose documentation lives in the source. The HTML is then produced from the markdown by a script in the repository, scripts/md-page.js, with a page title argument. The annotations are a separate artifact produced with docco, which renders the source with its comments inline, and a follow up step rewrites the asset paths afterwards. The README documents the manual invocation of that last one.

bash
    npx docco -o docs/site lib/lemonad.js

So there are two views of the same file, a reference manual generated from the doc comments and an annotated source listing, and both are rebuilt as part of the same script.

The todo list is a design document

The most unusual part of the README is the todo list, and it is worth reading as a statement of scope rather than as a backlog. It starts with the rest of the things and then lists Promises/A compatible functions, more monadology, logic variables, unification, generators and iterators, futures, laziness, a better memoize, data generators, merges, walking, a relational algebra, an into for objects, a check that anything working for array also works for arguments, and a change of the vocabulary so that sequence is used on input and array on output. Then it becomes playful, with entries like yggdrasil, undermine, reb, cljs, tables, bach.js, datalog, poems, shape declarations, a cheatsheet and a site. The functional point is that this is a deliberately small library. The list names the standard functional programming extensions that the author decided not to pursue, and the ones that are clearly jokes are the ones nobody should wait for. For an evaluator, the list is more informative than a feature matrix, because it tells you the shape of the library's ambitions and the direction it will not take.

Where lemonad fits, and where it does not

The honest comparison is with the utility libraries most JavaScript projects already carry. One of those libraries is in the influences list and offers a wide surface of collection and object helpers; lemonad offers a narrow one. If your need is a hundred array and object utilities, lemonad is the wrong dependency, because you would import most of a utility library anyway and add a second one for the rest. If your need is functional composition, currying, and a mutable reference with watchers and atomic style updates, the balance shifts, because those primitives are not the ones general utility libraries emphasise, and the mixin mechanism is a small, readable answer to object extension in a prototype based language. Two practical limits are visible in the repository. The version line is an alpha, with the manifest at 0.8.0-alpha.0, so the API can still change between releases, and the project publishes no GitHub releases, so there is no changelog to read between versions. And the type story is thin: the manifest lists no type declarations and the repository has no .d.ts files at the root, so a TypeScript project would need to describe this library itself. The last push was on 2026-07-29, so the code is not abandoned, but it is a single author experiment rather than a maintained foundation.

Editorial conclusion

Adopt lemonad if you want a compact functional core with currying, observable references and mixins in a single file, and if you are comfortable with a library whose API is still in an alpha line. It does not fit a project that needs a wide collection of array and object utilities, since the export list is roughly fifty names rather than a hundred and fifty, and it does not fit a codebase that needs type declarations, which the repository does not describe. Before you depend on it, check the version you install, because the README tells you to add version 0.7.4 to your dependencies while the package manifest already reads 0.8.0-alpha.0, and read the todo list in the README, because the features it jokes about are the ones that are deliberately absent.

Frequently asked questions

How do I install lemonad?

Add a dependency entry to your package.json file, with the README specifying the line "lemonad": "0.7.4". The package is plain CommonJS with its main entry at ./lib/lemonad, and the manifest allows any Node version.

What does lemonad give you over a general utility library?

The export list is built around currying with curry, rcurry and partial variants, a reference type with compare and swap support, a CASMixin, watchers through addWatch and removeWatch, and mixins. It is a narrow functional core rather than a wide collection of array and object helpers.

How do I run the lemonad test suite?

Run npm install to set up the project and install the dev tools including Jest, then npm test for the whole suite. A single spec file runs with npx jest test/specs/<name>.spec.js, and watch mode with npx jest --watch. The setup file test/jest.setup.js exposes the library global L for the specs.

How is the lemonad documentation generated?

The docs script chains a clean step, an API step and an annotations step, generating API markdown with jsdoc2md, checking that the markdown is not empty and failing the build if jsdoc2md found no parseable doclets, then rendering HTML with scripts/md-page.js. Annotated source views are produced separately with docco, which the README documents as npx docco -o docs/site lib/lemonad.js.

What is the current version of lemonad?

The README instructs you to add version 0.7.4 to your dependencies, while the package manifest in the repository declares 0.8.0-alpha.0. The project publishes no GitHub releases, so there is no changelog between versions to check.

Official sources

  1. fogus/lemonad on GitHub
  2. Issues
  3. License: MIT
  4. Project website
  5. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/fogus-lemonad.svg)](https://hysenlabs.com/projects/fogus-lemonad)

Was this useful?