HackerReposA FIELD GUIDE TO OPEN SOURCE
ProSponsor the shelf♧ 0
← Back to top all-time
fantasyland
fantasy-land
JavaScript2014–2026
fantasyland / fantasy-land

fantasy-land

Specification for interoperability of common algebraic structures in JavaScript

28Distinct people
32Mentions
1Explicit recommenders
10.2KGitHub stars
REPOSITORY AT A GLANCE

What to know before exploring

What it is

Specification for interoperability of common algebraic structures in JavaScript

GitHub

Where it is used

No documented product use was verified in the last source check.

What people are saying

If you are interested in learning about Algebraic structures and group theory from a very practical standpoint I highly recommend https://github.com/fantasyland/fantasy-land…

wrong_variable used a recommendation phrase. One indexed comment matches. This is a phrase match, not a verdict.

No classified warning is attached to this page. Read the discussions before treating silence as approval.

Also in these discussions

No other repository is repeatedly linked in the same discussions.

This week on Hacker News

Nov 7–Nov 14 UTC · Direct repository links and separately labeled related project stories. Indexed through 11/14/2026, 5:04:57 PM UTC.

No direct repository links were found in the indexed HN discussions over the past seven days. Older discussions are available below.

Mentions over time

HN mentions by year32 dated mentions

Observed mentions: 2014-02-16 17:19:19 UTC to 2026-07-02 23:05:22 UTC.

02462014-01-01 00:00:00 UTC to 2015-01-01 00:00:00 UTC (exclusive): 4 mentions; 1 submissions, 3 comments20142015-01-01 00:00:00 UTC to 2016-01-01 00:00:00 UTC (exclusive): 2 mentions; 0 submissions, 2 comments2016-01-01 00:00:00 UTC to 2017-01-01 00:00:00 UTC (exclusive): 7 mentions; 3 submissions, 4 comments2017-01-01 00:00:00 UTC to 2018-01-01 00:00:00 UTC (exclusive): 1 mentions; 0 submissions, 1 comments2018-01-01 00:00:00 UTC to 2019-01-01 00:00:00 UTC (exclusive): 6 mentions; 1 submissions, 5 comments2019-01-01 00:00:00 UTC to 2020-01-01 00:00:00 UTC (exclusive): 2 mentions; 1 submissions, 1 comments2020-01-01 00:00:00 UTC to 2021-01-01 00:00:00 UTC (exclusive): 1 mentions; 0 submissions, 1 comments20202021-01-01 00:00:00 UTC to 2022-01-01 00:00:00 UTC (exclusive): 2 mentions; 0 submissions, 2 comments2022-01-01 00:00:00 UTC to 2023-01-01 00:00:00 UTC (exclusive): 1 mentions; 0 submissions, 1 comments2023-01-01 00:00:00 UTC to 2024-01-01 00:00:00 UTC (exclusive): 2 mentions; 0 submissions, 2 comments2024-01-01 00:00:00 UTC to 2025-01-01 00:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2025-01-01 00:00:00 UTC to 2026-01-01 00:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2026-01-01 00:00:00 UTC to 2027-01-01 00:00:00 UTC (exclusive): 4 mentions; 2 submissions, 2 comments. Incomplete calendar period.2026*

* An incomplete calendar period is marked with an outlined bar. Its count is not directly comparable with a full period.

Counts come from the repository’s dated source evidence. Index cutoff: 2026-11-02 08:16:59 UTC.

View mention counts and date ranges
UTC ranges include their start and exclude their end. Select a period to filter the source evidence.
PeriodStart (UTC)End (exclusive, UTC)MentionsSubmissionsComments
20142014-01-01 00:00:00 UTC2015-01-01 00:00:00 UTC413
20152015-01-01 00:00:00 UTC2016-01-01 00:00:00 UTC202
20162016-01-01 00:00:00 UTC2017-01-01 00:00:00 UTC734
20172017-01-01 00:00:00 UTC2018-01-01 00:00:00 UTC101
20182018-01-01 00:00:00 UTC2019-01-01 00:00:00 UTC615
20192019-01-01 00:00:00 UTC2020-01-01 00:00:00 UTC211
20202020-01-01 00:00:00 UTC2021-01-01 00:00:00 UTC101
20212021-01-01 00:00:00 UTC2022-01-01 00:00:00 UTC202
20222022-01-01 00:00:00 UTC2023-01-01 00:00:00 UTC101
20232023-01-01 00:00:00 UTC2024-01-01 00:00:00 UTC202
20242024-01-01 00:00:00 UTC2025-01-01 00:00:00 UTC000
20252025-01-01 00:00:00 UTC2026-01-01 00:00:00 UTC000
2026 (partial)2026-01-01 00:00:00 UTC2027-01-01 00:00:00 UTC422

From the project README

An excerpt from the repository, fetched Nov 13, 2026.

Read the project’s introduction
Fantasy Land Specification (aka "Algebraic JavaScript Specification") This project specifies interoperability of common algebraic structures: Setoid Semigroupoid Semigroup Foldable Functor Contravariant Filterable (equals) (compose) (concat) (reduce) (map) (contramap) (filter) | | | \ / | | | | \ | | | \ / | | | | \ | | | \ / | | | | \ | | | \ / | | | | \ | | | \ / | | | | \ Ord Category Monoid Traversable | | | | \ (lte) (id) (empty) (traverse) / | | \ \ | / | | \ \ | / / \ \ \ | Profunctor / \ Bifunctor \ | (promap) / \ (bimap) \ | / \ \ Group / \ \ (invert) Alt Apply Extend (alt) (ap) (extend) / / \ \ / / \ \ / / \ \ / / \ \ / / \ \ Plus Applicative Chain Comonad (zero) (of) (chain) (extract) \ / \ / \ \ / \ / \ \ / \ / \ \ / \ / \ \ / \ / \ Alternative Monad ChainRec (chainRec) General An algebra is a set of values, a set of operators that it is closed under and some laws it must obey. Each Fantasy Land algebra is a separate specification. An algebra may have dependencies on other algebras which must be implemented. Terminology "value" is any JavaScript value, including any which have the structures defined below. "equivalent" is an appropriate definition of equivalence for the given value. The definition should ensure that the two values can be safely swapped out in a program that respects abstractions. For example: Two lists are equivalent if they are equivalent at all indices. Two plain old JavaScript objects, interpreted as dictionaries, are equivalent when they are equivalent for all keys. Two promises are equivalent when they yield equivalent values. Two functions are equivalent if they yield equivalent outputs for equivalent inputs. Type signature notation The type signature notation used in this document is described below:1 :: "is a member of". e :: t can be read as: "the expression e is a member of type t". true :: Boolean - "true is a member of type Boolean". 42 :: Integer, Number - "42 is a member of the Integer and Number types". New types can be created via type constructors. Type constructors can take zero or more type arguments. Array is a type constructor which takes one type argument. Array String is the type of all arrays of strings. Each of the following has type Array String: [], ['foo', 'bar', 'baz']. Array (Array String) is the type of all arrays of arrays of strings. Each of the following has type Array (Array String): [], [ [], [] ], [ [], ['foo'], ['bar', 'baz'] ]. Lowercase letters stand for type variables. Type variables can take any type unless they have been restricted by means of type constraints (see fat arrow below). -> (arrow) Function type constructor. -> is an infix type constructor that takes two type arguments where left argument is the input type and the right argument is the output type. ->'s input type can be a grouping of types to create the type of a function which accepts zero or more arguments. The syntax is: (<input-types>) -> <output-type>, where <input-types> comprises zero or more comma–space (, )-separated type representations and parens may be omitted for unary functions. String -> Array String is a type satisfied by functions which take a String and return an Array String. String -> Array String -> Array String is a type satisfied by functions which take a String and return a function which takes an Array String and returns an Array String. (String, Array String) -> Array String is a type satisfied by functions which take a String and an Array String as arguments and return an Array String. () -> Number is a type satisfied by functions which do not take arguments and return a Number. ~> (squiggly arrow) Method type constructor. When a function is a property of an Object, it is called a method. All methods have an implicit parameter type - the type of which they are a property. a ~> a -> a is a type satisfied by methods on Objects of type a which take a type a as an argument and return a value of type a. => (fat arrow) Expresses constraints on type variables. In a ~> a -> a (see squiggly arrow above), a can be of any type. Semigroup a => a ~> a -> a adds a constraint such that the type a must now satisfy the Semigroup typeclass. To satisfy a typeclass means to lawfully implement all functions/methods specified by that typeclass. For example: fantasy-land/traverse :: Applicative f, Traversable
Read the full README on GitHub

What Hacker News says

32 sources
I think it's worth reading this if you want to understand the initial motivation for introducing Monads to Haskell: https://homepages.inf.ed.ac.uk/wadler/papers/marktoberdorf/b... (And in the context of the previous paper, this one motivates Applicative well I think: https://www.staff.city.ac.uk/~ross/papers/Applicative.pdf) That said, I've never really understood the enthusiasm the industry has for introducing Monads outside of Haskell. As I understand it, at the time Philip Wadler wrote his paper, Haskell was pretty painful to use due to its adherence to purity. Monads were presented as a way to maintain purity while providing a principled way to support all kinds of effectful computations. But without some of the features Haskell provides (I'm thinking of typeclasses and HKTs in particular), and given that almost any language you'll be
Read the rest
introduced to outside of Haskell already has ways to do e.g. IO or whatnot, it almost always ends up feeling like bolting something on with not a lot of benefit. Don't get me wrong, I think there's value in stuff like https://github.com/fantasyland/fantasy-land --I find organizing how I think about computations around these algebraic concepts helps me a lot, personally. But that's distinct from introducing these concepts into day-to-day work in a non-Haskell language, especially on a team, which is often more trouble than it's worth unless everyone has already bought into it and is willing to deal with the meaningful friction introducing this stuff produces. I assume the overabundance of Monad tutorials and libraries has to do with the cachet of knowing this relatively obscure, intellectual thing and being able to explain it to your peers, or to be more charitable, perhaps it's a byproduct of getting excited about learning this new, distinct way to approach computation and wanting to share it with everyone. But the end result is that now we have tons of ridiculous tutorials and useless Monad libraries in tons of languages.
In Monad Tutorials Timeline
One great way to learn about FP is to read the documentation for Ramda.js [0] and tinker with their playground. For even more ideas check out Ramda-adjunct [1] and Fantasyland [2]. [0] - https://ramdajs.com/docs/ [1] https://char0n.github.io/ramda-adjunct/4.0.0/index.html [2] https://github.com/fantasyland/fantasy-land (A bit heavy on jargon) Note there is a python version of Ramda available on pypi and there’s a lot of FP tidbits inside JAX: 3. https://pypi.org/project/ramda/ (Worth making your own version if you want to learn, though) 4. For nested data, JAX tree_util is epic: https://jax.readthedocs.io/en/latest/jax.tree_util.html and also their curry implementation is funny: https://github.com/google/jax/blob/4ac2bdc2b1d71ec0010412a32... Anyway don’t put FP on a pedestal, main thing is to focus on the core principles of avoiding exte
Read the rest
rnal mutation and making helper functions. Doesn’t always work because some languages like Rust don’t have legit support for currying (afaik in 2023 August), but in those cases you can hack it with builder methods to an extent. Finally, if you want to understand the middle of the midwit meme, check out this wiki article and connect the free monoid to the Kleene star (0 or more copies of your pattern) and Kleene plus (1 or more copies of your pattern). Those are also in regex so it can help you remember the regex symbols. https://en.wikipedia.org/wiki/Free_monoid?wprov=sfti1 The simplest example might be {0}^* in which case we find: “”, “0”, “00”, “000” … a language with only one letter in the alphabet could still make all the natural numbers like that. With Boolean alphabet (two variant enum) we have {0,1}^+ which omits the empty monoid by using the + operator: “0”, “1”, “00”, “01”, … note this sequence will eventually yield every possible Turing tape, which is the same thing as listing every possible series of coin flip results assuming no coins land on their side (Turing’s undecidability paradox might be bullshit, but that’s another story) I meekly suggest, FP can save you days of headache if the only thing you do is clone your data and mutate the clone. Yes, that’s inefficient, so is dealing with infinite bugs due to state mutation in multiple places. Also, you can look into HAMTs / immutable / persistent data structures to juggle the pointers and copy-on-write on the storage data structure if you find yourself repeatedly cloning data then it would accelerate your stuff. Options include: Python: Immutables https://pypi.org/project/immutables/ Rust: RPDS https://docs.rs/rpds/latest/rpds/ and Im https://docs.rs/im/latest/im/ Rust isn’t great for letting you do FP things like other languages, but it does have the best type system imho which makes it the leading functional programming language right now imho. If you’re not using too many specialized python packages then I recommend using Rust instead, even for toy demos, as you can be more confident your code works without needing to run it and wait for a crash like you would in debugging python, and the tests also run faster in rust due to the incremental compilation. Use cargo-watch and you can retest your code every time you save your work. https://github.com/watchexec/cargo-watch I usually write a make command to cargo watch and rerun each test file : code file pair independently so then you won’t rerun your tests in other modules when you change the one you work on (faster but might miss stuff if you change API contracts which touch other parts of your codebase)
In Functional Programming 1
It was never really my jam, but I used to follow the up-and-coming fantasy-land specs with great interest. It just seemed like a sharp dedicated community of folks trying to figure out better fp & algebraic stuff. I'm not sure who trailed off - in general I feel like there's much less connection in tech world, that the tech twitter and every other ultra-active tech channel has somewhat decayed. https://github.com/fantasyland/fantasy-land Thanks for the links. I know I've seen @gcanti's name a thousand times already, but had utterly forgotten fp-ts.
In Ramda: A practical functional library for JavaScript programmers
I mean, you can go all the way to the deep end, but like any tool, there are good reasons to be pragmatic, and avoid just using a tool for its own sake. Sure, you can get lost in fantasy land[0] algebras if you really want to, but generally I see it as a pyramid of usage (i.e. a small number of people that care about the mathematics, a slightly larger group of library authors that use fantasy land and friends to inform API design decisions, and a larger portion of library consumers that benefit from the academic roots of those design decisions.) [0] https://github.com/fantasyland/fantasy-land
In Awesome Functional Programming
Yes, yes and yes. All of these concepts are variations of what has been done before in a number of ways. Mostly by "FP academics" who "live in fantasy land", until everyone else starts using them too. Transpiling, hooks and components have all been done (and done better) before React came along, but often they were laughed out as esoteric toys that have nothing to with "real programming". It's just hard to teach these concepts until you actually use them, and it's hard to get people to use these concepts unless they are included in something else that you need. The same happened early with React, both JSX and VDOM were laughed at by many developers because "they looked stupid" to people who didn't understand them and were used to one way of doing things. MVC+jQuery+templates was the flavour of the day. Same thing with TypeScript, FRP and
Read the rest
so on. Most likely, whatever concept is gaining momentum today, it's an exact or approximate copy, or in rare cases a novel remix of what has been researched 10-20 years ago, and used in production for 5 years before you heard about it on HN These people who like to apply category theory etc. in programming have heard this mocking of their work as stupid esoteric fantasy (and then seeing them become mainstream later) so often that they literally called one of their specs "Fantasy Land" https://github.com/fantasyland/fantasy-land There's still lot of work to be done. JavaScript doesn't even have proper immutable data structures natively, which would be a REAL low hanging fruit.
In Modern Javascript: Everything you missed over the last 10 years (2020)
Is the aim to teach functional programming as a paradigm or specifically "functional programming languages"? For High School, I would assume the first may be more important than the latter, and you may have good benefit from teaching FP as a paradigm in a language they are taught elsewhere or might have other reasons to use. You can spend less time teaching syntax and more time focused on patterns/practices. Which is to say, maybe start out in Typescript itself? There are a lot of great more functional paradigm-focused libraries out there in "Fantasy Land" [1] and "Static Land" [2]. A benefit to starting in Typescript as well would be that you could move to Elm or PureScript if there is time/interest and reuse many of the same libraries and/or even some of the earlier TS code/projects. It obviously seems like a trade-off that using a lang
Read the rest
uage that isn't "strict" or "native" to the functional paradigm, students might be tempted to avoid learning the functional paradigm and fall back to old habits. But on the other hand, that can still be a useful escape hatch to avoid frustration, especially with High School students who might have enough other stuff on their plates that some leniency might be handy/warranted (and for High Schoolers they shouldn't have that many "old" habits to fall back on anyway). It could be good teaching praxis to start with "Why did you fall back to doing this imperatively/OO/what-have-you? Did you try X? What if you explore Y that we discussed in class?" You and the students might learn a lot from dialogs like that. Just some thoughts. There's probably no "perfect" language, but sometimes the best language is the one people already know because that gets a lot of the basics out of the way and out of the focus. [1] https://github.com/fantasyland/fantasy-land [2] https://github.com/fantasyland/static-land
In Ask HN: Elm, PureScript, or ReasonML for a FP course?
Fun trivia, the promise absorption thing was dismissed when it was brought up, with the argument that the "ship had already sailed on that" and that the arguments for supporting promises of promises were too academic (in the detractors' words, it was "fantasy land"). Which then resulted in the creation of a specification called fantasy-land[1] as a form of mockery towards the "incorrect abstractions are fine" attitude. The goal of this spec is to standardize on functional algebra nomenclature in JS. [1] https://github.com/fantasyland/fantasy-land
In Examples of Incorrect Abstractions in Other Languages
Several comments here are along the lines of "I haven't done much monadic error handling but here's why it's bad." That's silly because the benefits of this type of programming can't be grokked until you use it on real projects.. it's honest-to-goodness not enough to look at small examples and judge whether it's worthwhile or not. There's a lot of this realization going around actually - for example Rust's main raison d'être is basically: "look - we _can_ write safe c/c++, some of us can even nail it perfect every time in small examples, but in large apps it's inevitable that we'll all make mistakes" Here's two issues with try/catch in real-world apps: 1. You aren't forced to write it. It's simply possible to forget that a function might fail (e.g. when that failure is defined as a side-effect). This is even worse when there's no type sys
Read the rest
tem forcing you to think about it. We all make this mistake! 2. You can't easily distinguish between expected errors and unexpected errors - and even where you can, dealing with that becomes a big mess. Unexpected errors (like "out of memory", "computer is quitting", "electricity is gone") - _should_ crash and burn and stop the app (unless you explicitly have a way to recover from it - in which case it's actually an _expected_ error). Letting the app continue on where there's undefined behavior is dangerous. Expected errors (like "user not found", "wrong password", perhaps even "network down") need to be dealt with. Every single time. Even in a function where it might not happen 99.999% of the time - that one rare time where it happens is especially hard to duplicate and fix. That said, I agree with the comments that say it's a bit awkward in JS, and much less effective without a type system forcing the right constraints. I like using FP-TS[0] with typescript for extra help at "transpile" time, but Sanctuary[1] (based on FantasyLand[2]) with the runtime checking turned on is pretty incredible too. With _some_ type system making sure that we're following the rules, monadic error handling is definitely more elegant and safer than try/catch. [0] https://gcanti.github.io/fp-ts/modules/ [1] https://sanctuary.js.org/ [2] https://github.com/fantasyland/fantasy-land
In Elegant Error Handling with the JavaScript “Either” Monad
Personally I’m not saying JavaScript “counts” as FP — which is why the post says “unless _you_ count”. ;-) But there are certainly FP subcultures in the JS community which only use the functional subset: https://github.com/jfmengels/eslint-plugin-fp https://github.com/fantasyland/fantasy-land https://ramdajs.com/ That subculture is what I was referring to. If you’re splitting hairs over such definitions without acknowledging the cultural aspect and use that as a hiring criteria I wouldn’t want to work with you either.
In Things I Don’t Know as of 2018
I'm a big fan of @mhashemi's work in Python in general, even if I don't use Boltons personally. The discussion regarding inclusion in the stdlib is sensible, and I fully agree with @mhashemi's comments. See similar discussions, for instance, regarding dataclasses vs. attrs (https://github.com/ericvsmith/dataclasses/issues/19). Sometimes, however, it's a bit annoying when something that you think should be widely available isn't included in the stdlib. The cons of course are: - Fragmentation (several project pursuing similar objectives) - Not being able to use a powerful construct to simplify code in the stdlib itself (the stdlib can only depend on the stdlib). Regarding, for instance, functional programming, I maintain a list of interesting projects in this domain in Python: https://github.com/sfermigier/awesome-functional-python/blob...
Read the rest
There are at least half a dozen libraries that strive to achieve similar goals, and would probably benefit from being included in the stdlib (at least partially). It's hard to pick a winner among the list (like other in this thread, I went with toolz). I believe that a way to solve (at least partially) this conundrum could be to work on some common specifications, like the JS community did with Fantasyland (https://github.com/fantasyland/fantasy-land), and then let projects implements the specification the way they want. WDYT ?
In Boltons: A set of BSD-licensed, pure-Python utilities

Showing the 15 most recent of 32 sources. Enable JavaScript to search and browse every indexed mention.

MAKE YOURSELF AT HOME

A few shortcuts

/
Search the collection
?
Open this guide
Esc
Close dialogs and navigation

Your saved repositories and interests stay in this browser.