Skip to content(if available)orjump to list(if available)

Why Fennel?

Why Fennel?

161 comments

·April 13, 2025

benwilber0

I love seeing new languages targeting the Lua runtime. I've been adding Lua scripting support to pretty much everything I make now. I recently made my SSE server programmable with Lua and it's extended the functionality far beyond what I would have had the patience and time to do myself. Highly recommend Lua with mlua-rs Rust bindings.

[0] https://tinysse.com

[1] https://github.com/benwilber/tinysse

[2] https://github.com/mlua-rs/mlua

ronsor

I don't have any use cases in mind right now, but this looks cool. You should try posting another Show HN.

giraffe_lady

I would love to see a stripped back ML-style language that targets lua, just something like ocaml's type system and exhaustive pattern match right on top would be all I need. There have been a few attempts but nothing I know of that got usably far and is maintained.

There might be a way to get standard ML to output lua or something but I'm not that familiar with it. I think it would be an incredible fit for a third backend for gleam, but they say they aren't adding any more beyond erlang and js.

Vedor

I think that LunarML [1] could fit this niche quite well. It's a StandardML compiler that targets Lua. I can't tell much more as I've only played with it a little and don't have much experience with ML languages in general, but it looks promising.

[1] https://github.com/minoki/LunarML

HexDecOctBin

You might be able to repurpose CSharp.lua[1] to compile F#

[1] https://github.com/yanghuan/CSharp.lua

Graziano_M

Fennel is nice. I converted my neovim config[1] to fennel and haven't looked back.

[1]: https://github.com/Grazfather/dotfiles/blob/master/nvim/fnl/...

qrobit

Fennel is indeed nice and I rewrote my config in it too, but looked back ~2 years later and rewrote it again in Lua. I think Fennel for configuration is not justified and just adds complexity. Also the tools are not there: two existing language servers[1][2] can't compete with Sumneko's Lua language server[3] and they are fennel-exclusive and clueless about Lua code. I still like Fennel for writing more complicated code (my plugins: [4][5]) because of neat features like pattern matching and structural decomposition, both are surprisingly robust.

[1]: https://git.sr.ht/~xerool/fennel-ls/

[2]: https://github.com/rydesun/fennel-language-server

[3]: https://github.com/LuaLS/lua-language-server

[4]: https://gitlab.com/repetitivesin/16cm.nvim/-/tree/main

[5]: https://gitlab.com/repetitivesin/madol.nvim

no_wizard

I find most niche / less popular languages lack the developer tools ecosystem in ways that simply hinders adoption by more devs.

A good and comprehensive LSP for example. It really needs to be on par with other languages to increase adoption

iLemming

> I find most niche / less popular languages lack the developer tools ecosystem in ways that simply hinders adoption by more devs.

Niche languages often serve specific purposes that don't require broad tooling. They also sometimes can leverage tooling from more popular languages. Less popular doesn't necessarily mean less capable - some niche languages have excellent tooling in their domain. Not to mention that not all developers need the same type of tooling or prioritize certain set of tools equally, like for example, for me personally - homoiconicity and REPL-connectivity in a language are far more important than LSP or some other things.

jbjbjbjb

I’ve been dipping my toe in Lua and found some ways to achieve pattern matching of sorts and there’s a package called Tamale too but I’m not sure if that is used much.

hyperbrainer

If only there was an editor which could act as an interpreter for Lisp directly ...

OhMeadhbh

I've been using EMACS since it was TECO on TOPS-10. Not a day goes by that I don't spend at least an hour with it. But it is long in the tooth and the abstractions it exposes are as advanced as they can be without breaking reverse compatibility. It is one of the few packages I think would be improved by a fully-supported package manager. E-Lisp is a warren of inefficiency, notational paucity and half-implemented tools. If someone wanted to build an emacs-like text editor in Lua or Fennel, I would absolutely sign up as a beta tester (assuming the key bindings were mostly the same.)

Graziano_M

I understand it's improved, but Emacs was always too slow for me.

Additionally, in my workflow I open my editor across many many terminals, the startup time alone prevented this. With emacsclient it was faster, but I specifically DON'T want to have a window that shows all my other open files.

iLemming

> I specifically DON'T want to have a window that shows all my other open files.

There are multiple different ways of separating project/workspace/etc. contexts in Emacs - tab-bar mode, persp.el, etc.

pdimitar

Wake me up when its authors realize most of us don't want to "hack" our editors. They're still stuck in 1980. We actually have to pay bills and want to spend time with our families and go out in nature.

I appreciate customization; that's why I moved to Neovim and not to a full-blown GUI IDE (and I'll never use those). But that editor you speak of practically requires me to fix the idiocies of plugin authors that can't be bothered to run 7 tests on their code.

I get it, a lot of programmers are cult followers. I was as well. At one point though, pragmatism should prevail. The editor should ideally be non-laggy and not spit warnings after I move from one buffer to another. Just embarrassing.

Zambyte

I haven't really touched my emacs config in years. I just set it up how I wanted and now I use it to pay my bills. It sounds like the flexibility was just too tempting for you to not hack on it when you should be doing other things.

threatofrain

https://janet-lang.org

Also by the same author.

monomers

I like Janet a lot, and have been using it for small personal projects for about a year.

But it does come with some design decisions that I'm a bit ambivalent about and for which I haven't found a good explanation:

- No persistent data structures. I guess this has something to do with limitations of the GC?

- unhygienic macros combined with lack of namespaces. XOR those two choices would be fine, but the combination is janky

- Somewhat peculiar choices in syntax. It's neither Scheme, nor is it Clojure. # starts comments, ; is splice, @ marks literals as mutable...

nine_k

Janet is very small, apparently smaller than Lua, and is also intended to be embedded into native-code programs. Hence, I suppose, the decisions that make it "too" simple: it apparently is not intended for writing large amounts of code.

2mlWQbCK

I prefer Janet, but Fennel is great in places Lua is already supported, like in Löve2D.

https://git.sr.ht/~benthor/absolutely-minimal-love2d-fennel

roxolotl

One thing I've found that's really nice with Fennel + Love2D is you can even do hot reloading with nvim+conjure[0](I assume emacs too). I assume there's a way to hot refresh with just straight Lua but it feels very natural to do with a lisp.

0(example config): https://github.com/TheBlob42/love2d-fennel-neovim

grzm

I believe Fennel was originated by Phil Hagelberg (technomancy)

https://git.sr.ht/~technomancy/fennel-lang.org

Janet looks like is by Calvin Rose (bakpakin) https://github.com/janet-lang/janet/graphs/contributors

lc9er

I’m pretty sure Calvin created Fennel and Phil took up the reins when Calvin moved on from the project.

grzm

I stand corrected:

    % git remote -v
    origin https://git.sr.ht/~technomancy/fennel (fetch)
    origin https://git.sr.ht/~technomancy/fennel (push)

    % git log --reverse
    commit 9afe4338ed1816a759cb4b120f89e8f67159ce16
    Author: Calvin Rose <calsrose@gmail.com>
    Date:   Sun Aug 7 18:50:34 2016

        First commit.

    commit b62a24853e24662f76932a2a81bb77cc25704491
    Author: Calvin Rose <calsrose@gmail.com>
    Date:   Sun Aug 7 19:05:40 2016

        Add some examples.

    commit 5e3e0fe11e4f56007b3523e54d81d55280ef2204
    Author: Calvin Rose <calsrose@gmail.com>
    Date:   Tue Aug 9 08:27:43 2016

        Update README.md

sgt

Dammit, Janet! Ok, looks good. I'll need to look into it.

vanderZwan

Whomever downvoted you probably never saw the Rocky Horror Picture Show

null

[deleted]

AlienRobot

>by the same author

What? People are just creating new languages these days as if they were Javascript libraries?

Let's say I wanted to make my own programming language. What's the easiest way to prototype it in a way I can share it with the world? Are the programming language development toolkits that come with a tokenizer library and things like that? Should I write my own program to output machine code? Or maybe it's easier to just transpile to Javascript?

calebkaiser

The author, Calvin Rose, is a (I assume pretty great) compiler engineer at NVIDIA who has a personal affinity for LISPs and Lua: https://bakpakin.com/

I don't think the average programming language enthusiast is maintaining multiple well-known languages.

AlienRobot

Interesting. I saw another link here of someone who insists on making C# run everywhere, now someone who insists on LISPs.

I really want to try making a language that is imperative, like really imperative, where every line must start with a verb, just to see what it would look like.

jodrellblank

Crafting interpreters by Robert Nystrom could be a place to start - https://craftinginterpreters.com/

The author posts on HN as ‘munificent’, I think.

tmountain

Great book—as an entry point for designing languages.

ninalanyon

I thought almost all programmers created a language or two in the course of their careers or hobbies.

You can make a simple language very easily if you design the syntax carefully and restrict its capabilities. It all depends on what you need it for.

In my case I needed a way to create reports from a Turbo Pascal program (TP3 for DOS I think) without having to edit the program and ship a new version. So I made a simple report generating language. It had simple for loops, all variables were global, tokens were all separated by white-space, no user defined sub-routines or functions, a set of predefined procedures specifically designed for the report generating function, arithmetic expressions that were only allowed in assignment statements, interpreted not compiled.

It was actually quite easy to do but of course was not a general purpose language. These days it might be simpler to embed Lua.

geekraver

Apart from Forth, Lisp and Lua, Tcl also deserves mention as a small embeddable language. Not sure of its state today; I think by v8 it had started to get more complex, but its original incarnation was very simple. I remember getting Ousterhout’s book and being so enamored with the elegant design that I felt compelled to just implement it myself from scratch, which took just two days.

torginus

I do not understand the appeal of LISPy languages. I get that the parser is simple and elegant, but I believe the developer (of the compiler in this case) should serve the convenience of the user, not the other way around.

Writing code like this is cumbersome and unnecessarily symbol heavy, and reading it isn't really nice as well.

I'd rather have the language add that extra complexity into the parser than have me stare down these endless paretheses. Parsing something C-like is not that, hard, trust me, I've done it

endgame

Focusing on the runtime's parser is a red herring and I think a common error in lisp advocacy.

Even if I didn't the full power of a lisp macro system, it is an absolute joy to manipulate programs written in s-expressions. Being able to cut/copy/paste/jump-[forward/back] by sexpr is really convenient, and often done nowhere near as well in other languages. I think this is because until the invention of tree-sitter and LSPs (and the former isn't yet widely adopted in editor tech), most editors had regex-based syntax highlighting and some kind of ad-hoc "parser" for a language. This makes them less aware of the language the developer is editing, but was probably a pragmatic design decision by editor implementers: it's easier than writing a full parser and means the editor can still assist even if a program is syntactically ill-formed.

torginus

It does sound interesting, and I'll look into Lisp, can you give me some advice on what's the best way to learn it?

On your other point, I've programmed in many languages in many years, and mostly I did some in an environment with an IDE, or powerful language-specific tooling (not tree-sitter) that had a proper good understanding of the syntax and semantics of the language used.

Zambyte

If you learn better by video than by reading, the Structure and Interpretation of Computer Programs lectures by Abelson and Sussman are spectacular. I have watched the entire course multiple times. The SICP book also receives a lot of praise, but I have yet to read it myself. They specifically use Scheme, but most of the knowledge can be translated to other Lisp dialects as well. The biggest difference between the different Lisp dialects are the macro systems and the standard libraries, so getting started and learning it doesn't really matter which one you choose. GNU Guile or Racket would be easy to use to follow along with SICP though.

eager_learner

A good text to make you aware of the power of Lisp is "The Anatomy of Lisp" by John Allen (MIT). It's an old text but they don't write books like that anymore.

iLemming

> what's the best way to learn it?

What's the best way to learn programming in general? For me, is to try to build something. Find a problem, pick a Lisp, start building.

Just make sure to have two things: structural editing and the REPL. Without these two, Lisp may feel awkward. But when you have the ability to quickly move any expression around, transpose them, etc., - writing programs becomes like composing haikus or something. You basically will be moving some "lego-pieces" around. With the connected REPL, you will be able to eval any expression in-place, from where you're writing your code.

I started without these and indeed, that was challenging. Having to balance the parentheses by hand, counting them, omg, I was so obtuse, but I'm glad I didn't give up. You don't have to go too crazy - in the beginning, something that automatically balances out the parens, or highlights them when they are not, and lets you grab an expression and paste it somewhere else would be good enough.

And the REPL. Shit, I didn't know any better, I thought I was suppose to be copypasting or typing things into it. That is not the way! Find a way to eval expressions in-place. Some editors even show you the result of the computations right where the cursor is.

I have done years of programming prior to discovering Lisp, and I don't really understand how I was okay without it. I wish someone has insisted to try it out. Today I don't even understand how can anyone identify as a programmer and "hate" Lisp, just because they have stared at some obscure Lisp code for like two minutes at some point.

OhMeadhbh

also, for what it's worth, I've moved on to mexp in my old age. Just easier to figure out where things begin and end without all those parens. And they more-or-less mechanically convert to sexpr when you need them to.

And back in my day you couldn't get a CS degree without a class on parsing and interpreting structured data. Usually it was the compilers class. Now we don't require kids to take a compilers class so an entire generation doesn't understand why regexes don't work in all cases. When kids in my organization try to "parse" HTML or XML with regexes, I hand them a copy of the O'Reilly Lex and Yacc book. And when they come back saying they can't understand it, I hand them the Dragon book. I guess I just think we should all feel that particular pain. Sorry for the digression, but I was triggered by "regex" and "parser" used in the same sentence.

n4ture

I do not understand the appeal of non-LISPy languages. I get that most people are used to reading it and that they are efficent, but I believe the developer (of the compiler in this case) should serve the convenience of the user, not the other way around.

Writing code like this is combersome and unnecessarily symbol heavy, and reading it isn't really nice as well.

I'd rather have the language add those extra parens into the parser than have me stare down these endless semi-colon, linebreaks or indentation. Parsing something Lisp-like is not that, hard, trust me, I've done it.

NewsaHackO

This doesn't really resonate with people though, as most people are more familiar with C-style notation. Also:

>Writing code like this is combersome and unnecessarily symbol heavy

Does not make sense in this context, as it mainly applies to Lisp-like languages that uses parentheses heavily.

n4ture

Yeah was going to change that part too for something like "Writing code like this is verbose and spans too many lines", but then I just thought it'd be better if it sounded more like the parent comment.

And I understand it doesn't resonate with most, I just wanted to highlight how the initial parent comment was very subjective and not very substantive, some people didn't take the joke so well, I guess it could've sounded a bit passive aggressive. I personally enjoy both C-like and Lisp-like syntaxes and languages, I do have a sweet spot for Forth tho.

But back on topic, Fennel is a great language, working with Love and Fennel is really nice. And if the parentheses can seem off-putting for some, I'd highly encourage to give it a shot as you can quickly get past it and see how comfy it feels to have your statements properly demarkated.

S-expr shine the most when working with XML-like structure. Spinneret[1] was the most fun I ever had working with HTML, every other templating engine feels subpar now that I have tasted that sweet nectar..

[1] https://github.com/ruricolist/spinneret

smnplk

>> as it mainly applies to Lisp-like languages that uses parentheses heavily.

This is so wrong. Lisp does not use parentheses heavily. It doesent even use more parens than any C like language. I just dont understand the fixation with parentheses. The power of lisps comes from the fact that everything is an expression. Someone can correct me if I am wrong, since I only have experience with functional lisp Clojure, but I believe other lisps are more or less similar.

So if everything can be evaluated, then you can have a really great REPL experience. You can be inside your favorite editor and have the tightest feedback loop possible. So the absence of statements is actually a great feature of the language which improves ergonomics.

fuzztester

>Does not make sense in this context, as it mainly applies to Lisp-like languages that uses parentheses heavily.

I had read, some years back, that someone did an actual calculation / demonstration that showed that the number of symbol / punctuation characters in Lisp is actually less than in C-based languages, for a block of code with equal functionality in both languages.

I don't have the reference handy. Someone here may know of it, and post it.

torginus

My understanding is that Lisp and most functional languages map very well to PL theory and how compilers and interpreters manipulate programming languages (functions as graphs of code, types as contracts etc.), while procedural languages map well to how CPUs execute programs, and the abstractions operating systems provide (functions as mappable pieces of memory, types as memory or register layouts etc. )

Guvante

Let's be real in most situations it doesn't matter. One "statement" per line is bog standard. Whether that statement is surrounded by parens or ended in a semicolon isn't impactful for reading.

LISP is only better when you add source code transformation (which is way easier with its source code looking like the transformed code). But then you introduce "everyone can write their own syntax" which is good and bad given the history of DSLs...

jdminhbg

> One "statement" per line is bog standard

This isn't really true. Most non-Lisp languages I work in, like JS or Ruby or Python, have things like long_expression =\n long_other_expression, or long_expression\n.another_long_expression\n.another_long_expression.

zelphirkalt

When writing code you are transforming it all the time. Having only expressions (mostly) comes in very handily. It is called structured editing of code.

vfclists

Are n4ture and torginus the same person?

Why the exact repeat of the earlier post under a different name or some bots at play here?

bmn__

It's not an exact repeat.

chongli

The appeal can be seen with paredit-style [1] editor plugins. They give you the power of working on trees rather than text. When you master the paredit way of editing you’ll wish you could do that with every language.

[1] https://paredit.org/

evdubs

Try defining data in C. Try extracting data from that data you've defined in C.

If you can understand the appeal of having JSON in JavaScript, you can understand some of the appeal of Lisp.

Vegenoid

I’m having trouble understanding what you mean, if you could provide or link to an example I’d appreciate it.

evdubs

Sure. Here's a comment with more of an explanation:

https://news.ycombinator.com/item?id=36158974

f1shy

If you parse things with structure, and the structure is unknown in advance. In C(++) you have to generate all dynamically, and is very complex.

In other systems, you can just read the object, and the structure comes with it.

nimih

I personally find lisp-y syntax to be pleasant to write, and to generally be straightforward and easy to read. It's interesting to hear you have the opposite opinion, though.

yuppiemephisto

> I’d rather have the language …

check out Lean 4 then. Its syntax system is based on Racket but —instead of parens— implements stuff like [JSX syntax](https://github.com/leanprover-community/ProofWidgets4/blob/d...) and a [maze](https://github.com/dwrensha/lean4-maze)

shakna

Most Lisp-y language have multiple parsers. The frontend may be that one, or it might be another. Racket has hundreds of frontends [2], Scheme has Wisp [0], and so on.

The ideal part of it comes down to the language being able to manipulate itself. Make the tokens an array, that you can shift, inject and/or mould into what you need.

That being said, that power isn't isolated to just Lisp-y. A few stack languages have it, like Forth, or to plug myself [1]. However, stack languages are a bit harder to optimise.

It isn't that they don't want a complicated parser. It's that you want to be able to easily modify that parser as its running, without hitting TeX levels of performance slowdowns.

[0] https://srfi.schemers.org/srfi-119/srfi-119.html

[1] https://git.sr.ht/~shakna/jstack

[2] https://doi.org/10.1145/3580417

caddzooks

Consider the following LISP function that performs a transformation of an MxN matrix:

(defun transpose (matrix) (apply #'mapcar #'list matrix))

Based on my own experience I think I can say that It isn't until one has acquired a reasonable amount of experience with the language that they can fully appreciate its power.

satvikpendem

Now try it with BQN

R4tY9jQ2

Fennel's approach of compiling to Lua while maintaining meta-programming capabilities is elegant. The syntax reminds me of Clojure, but without the JVM overhead. For embedded systems or game development, having both functional idioms and Lua's tooling seems like a powerful combination.

quectophoton

> Fennel's approach of compiling to Lua while maintaining meta-programming capabilities is elegant.

Yeah, it is very nice to work with.

The only tiny "complaint" I have is that it doesn't compile to pure Lua, but instead assumes you'll be running it together with Lua's libraries.

I say this because, for me, the places where I'd like to use Fennel have a lot of overlap with the places where I'd like to use Lua without loading any of the provided libraries (e.g. embedding Lua into other software, instead of using it standalone).

giraffe_lady

Wait what do you mean? If I understand you correctly I use fennel for this all the time, I just copy the compiled lua into the place the program expects to find lua scripts.

MyOutfitIsVague

Sandboxed lua can't assume it has access things like debug libraries or any of the file IO, among other things. Many setups pretty aggressively remove and/or patch libraries and even large parts of the default global table. Assuming a vanilla lua library environment can make a project like this unusable in many places.

quectophoton

I might be remembering wrong on where the problem was exactly, but it was either the generated code, or the code for the Fennel transpiler itself.

I just know that I tried to use it without loading Lua's libraries (i.e. without calling the `luaL_openlibs` function or equivalent) and was unable to.

> I just copy the compiled lua into the place the program expects to find lua scripts.

Yeah most existing programs just load all Lua libraries by default, so that's generally not an issue.

My post is more from the point of view of embedding a restricted Lua interpreter into a program (i.e. only Lua-the-language, not Lua-the-language-plus-its-libraries) while still supporting Fennel.

---

EDIT: Just checked, the Fennel code `(lambda [foo bar] bar)` compiles to Lua code that calls `_G.assert`.

giraffe_lady

Another spot it's great for is in legacy lua programs that you inherit from who knows where, which in my experience is a lot of the live lua out there. It hooks into the module loader system so you can just freely mix functions and tables between the two.

cardanome

Fennel is pretty nice.

I wish it had gradual typing support though or at least allowed for type annotation for static tooling. Not that dynamic typing isn't a valid choice but with more and more languages getting gradual typing support it is hard to go back.

I guess we could build something like Coalton but for Lua.

codr7

I've been working on something along those lines in eli:

https://github.com/codr7/eli?tab=readme-ov-file#type-checkin...

tmountain

Nice looking language! What’s the status? Is it stable?

codr7

That would be a question of definitions :)

It's mostly addition by now, rare that something disappears or changes significantly.

No prod use by anyone afaik.

HexDecOctBin

I did find this, though it seems runime only: https://github.com/dokutan/typed-fennel

Maybe a static system can be built upon it.

jlundberg

Semi-related for those looking for other languages built on top of Lua:

https://moonscript.org/

kras143

I believe that people who complain about parens have not coded in Lisp (atleast not enough)! Once you get over the "parens", the homogeneity of the language shines through and you will appreciate why some people like me never get over Lisp.

lerax

it's kinda funny that whole noise about parenthesis. For a experienced Lisper parenthesis are so meaningless that can be ignored by reading good indented code, however... for a newbie, the amount of parenthesis can be a real nightmare. All that can just be properly solved by using a decent editor that support good parenthesis edition... like emacs. Truly funny. I've been on this community for more than 10 years and always the same thing.

tmountain

Great for casual and fun game development. TIC-80 has direct support, and it’s pretty easy to go from fennel to PICO-8.

duncanfwalker

The comparison with Closure is really interesting. They make the point that they do less reinvention of Lua than Closure does with Java - functions, standard library, tooling. I'd love to know why. Is it just that Lua has less problems than old-Java

TinkersW

I'd guess a major reason is that Java is statically typed, and Lua/Fennel are dynamic; making it easier to reuse any existing libraries.

frogulis

I get the impression that Fennel is intended as a different/better interface for Lua.

In contrast, Clojure is intended as the language Rich Hickey wanted for writing the sort of applications he wrote, and the JVM happened to be a powerful (and already existing) platform that was suitable for doing that.

nine_k

JVM has no notion of a function, only of a method! You don't have something to piggy-back on. Java stdlib from 15 years ago (to say nothing of 25) is a realm of heavy OOP and mutability everywhere, something you may not want to adapt your Lisp code to.

macmac

Clojure

giraffe_lady

I'm not sure if this was the up front reasoning but a lot of lua code is run in situations where you don't have full control over the runtime or distribution method.

So anything that requires C libs would automatically rule out fennel for a lot of projects that are essentially using someone's lua api as the target platform. Roblox, mud client scripting, openresty, that sort of thing.

And these environments usually have so much added to them, pcre, stdlib extensions, class systems etc fennel works best not making any assumptions about any of that. It's just straight up the lua semantics, and so anywhere lua works it works. I've used it a lot and originally recoiled from this decision but now I think it is genius.

z5h

Ok I’m genuinely convinced I’d be happier using Fennel than using Lua in instances where I need to use Lua. I’m not currently using Lua for anything. Maybe if I write a Pico-8 app…