Fennel – Lisp in Lua
fennel-lang.org
fennel-lang.org
Edit; not bytecode, thanks
So yeah, blazing fast, with a decent macro system and fixing some of the odd corners of Lua at compile time. It's really a great little thing (it's 2k lines of lua, so super easy to embed/ship too).
There are at least two other Lisps in Lua
[Edit] I recalled this older HN thread with some relevant information: https://news.ycombinator.com/item?id=16566825
tl;dr Urn is a much bigger language that happens to compile to Lua as an implementation detail. Fennel is much closer to Lua and is dramatically simpler, only diverging from Lua semantics when the changes can be implemented purely at compile time. (immutable locals, blocking accidental global references/setting, etc) The compiler output from Fennel tends to be pretty readable and looks a lot like the input.
If you need to write code that runs in the browser, Lumen is one choice, but you can also run Fennel in the browser using Fengari: https://fengari.io/ I know next to nothing about frontend development but was able to integrate Fengari into https://fennel-lang.org to get the live REPL working with ease.
https://news.ycombinator.com/item?id=17958650
are swaying me to spend some time with Lumen this weekend to understand how it compares to Fennel. The Lumen examples were pretty impressive and it works for JavaScript too.
> (fn fib [n]
(if (< n 2)
n
(+ (fib (- n 1)) (fib (- n 2)))))
which seemed to take, but then upon trying (print (fib 10))
it spit out the following: [string "return print(fib(10))"]:1: attempt to call a nil value (global 'fib')
Do I need to initialize fib before in the repl?I like Lua quite a bit and it is of course, extremely fast, but I wish there were good "batteries" along with other stuff that I've come to expect from Python/Ruby et all. Of course, I've coded up some of those libraries myself as well. :)
Just wondering what people's general thoughts on this are.
[1] jsoftware.comBit odd statement, considering that LuaJIT afaik targets Lua 5.1 compatibility with some 5.2 extensions, while main Lua is currently at 5.3. I guess the question is what version Fennel is targeting
It works great with Fengari for client-side scripting; in fact this is what we use on the web site for the live REPL. We have run some tests against other obscure implementations such as Luerl and Rembulan but have encountered some bugs in those compilers that need to get addressed before they get integrated into the test suit.
The ecosystem can be somewhat confusing, because much of what would look like abandoned packages in most ecosystems are more like completed packages, but speed hasn't been a real failing of Common Lisp for a long time now. Talked about a ton, of course.
Fennel piggy-backs on a known and widely deployed language / VM.
This gives them different capabilities, and very different possible adoption curves.
As a matter of fact the only game in town for embedding CL code is ECL which: 1) relies on the Bohem garbage collector 2) is LGPL licensed
Both points have cons which might discourage embedding of Common Lisp code in other applications. Matters would be different if there was something like a CL to C transplier adopting a generational GC distributed with a MIT/BSD like license.
sorry what ? where does this meme comes from ? Most CL implementations are at best multiple times slower than your average JITted language
Maybe you could post some links to benchmarks that demonstrate your claim.
(I recognize this is unscientific and anecdotal, but I'm just trying to point out that it would take significant evidence to convince me SBCL is faster than Luajit, because my experience is the opposite.)
http://factor-language.blogspot.com/2010/05/comparing-factor...
All four languages have improved over the last 8 years, but you can see SBCL and LuaJIT are in the same ball park, each winning on some tests. My recollection is that SBCL usually "wins" in the number heavy tests like Mandelbrot, but I don't have time to dig up the links.
https://old.reddit.com/r/programming/comments/6eg0x/where_ar...
> the inner loop of mandelbrot is now identical (at the ucode IR level) to the IR generated by a C compiler. All type checks have been eliminated and only the pure (statically typed) FP adds/multiplies are left (the remaining task is to transform the ucode to the best possible machine code -- working on it). Similar results can be obtained for other numeric loops.
^ This is from a ten-year-old post about LuaJIT optimizations.
Regardless, though, I think it’s clear that there are already fast Lisps.
I might try again with a different program.
The docs for Lumen are a bit sparse, but it looks like it doesn't make globals opt-in or make you flag locals as mutable the way Fennel does. IME calling these things out explicitly makes certain kinds of bugs easier to catch. Fennel also allows for optional arity checks on functions.
I would expect that Lumen's keyword arguments would cause some complication when interoperating with Lua, which doesn't have them. In addition, cross-compiling to both JS and Lua means that it can't seamlessly support multiple return values, which are used pervasively in 3rd-party Lua libraries.
As I mentioned elsewhere, Fennel can run in the browser with Fengari, but it's a very different approach because Fengari includes a full Lua VM. This means there's some overhead to load the VM (~220kb) but once it's loaded you get access to coroutines, which are a much nicer way to code non-blocking functions than callbacks.
But these are just my initial uninformed impressions.
I am going to try Fennel, specifically look over your work on Fennel and the game you did. I am sure it will speak tons to my questions. I can always try and duplicate efforts in Lumen if I really want to know for myself if it is a good fit for me and my needs. Thanks!
Why would one call it 'Lisp' (which stands for 'Lisp Processor), when for example it does not do list processing as in Lisp?
> (list 1 2 3 4)
[string "return list(1, 2, 3, 4)"]:1: attempt to call a nil value (global 'list')
> (append '(1 2 3) '(3 4 5))
Compile error in '3' unknown:3: cannot call literal valueMaybe someone can answer - why does fennel description insist on macros as compile time feature? I'm interested in live coding and self-modifying code; is there a speed penalty or some other reason why Fennel would be a bad option?
Instead of using bitmaps/meshes, the user starts with single primitive (y < 0 half-plane) and applies series of transformations (wrap, intersect, linear transform...) to sculpture it into desired shape. This scene description looks and behaves both like JSON tree and S-expressions.
For interactivity, I would like to have a lisp-like language that's visualized as tree. The user would execute 'macros' to modify existing code, for example to wrap a function into a loop or to make a mirror reflection of existing graphics. The host should make sure that code is always syntactically correct and should provide default primitives when constructing new code, that will be replaced or modified by user.
Here's some WiP screenshots: [0] https://raw.githubusercontent.com/jmiskovic/arbo/master/medi... [1] https://raw.githubusercontent.com/jmiskovic/arbo/master/medi... [2] https://i.imgur.com/qzb6cC0.gif
This just means that it's possible to ship the compiled code on its own and have no dependencies on Fennel at runtime. It doesn't mean you can't ship the compiler if you want to; the choice is up to you. In fact, I strongly recommend in most cases shipping the compiler so you can write and refine your code interactively as the program runs. It's helpful to think of "compile time" as a subset of runtime; it's just that portion of runtime when the function that's running happens to be the compiler!
Fennel is very well-suited for live-coding; I used this heavily when writing my entry to the Lisp Game Jam this spring. I blogged a bit about how live-reloads interact with the Lua module system here: https://technomancy.us/189
What about Common Lisp libraries? would they be transpiled too?
Is there even a site with Common Lisp libraries written in common lisp to be the source to be transpiled into Lua ?
Yes, easily.
With a little bit more work you could load the Fennel compiler up server-side so it could do the compilation for you and support Fennel "natively". I have done a similar process with TIC-80 despite knowing very little C: https://github.com/nesbox/TIC-80/pull/597
> What about Common Lisp libraries? would they be transpiled too?
No, Common Lisp is a completely different language with little in common with Fennel.
In other words: writing a custom language for each application in the name of efficiency or more elegant patterns seems to make perfect sense.
I wonder if there's a master list of "this language X transpiles to language Y and imitates language Z".
(there will be a warning about loading unsafe scripts as the original file loads jquery under http)
Perhaps for learning purposes you would benefit from lisp that has tools with debugging capabilities, like Racket.
On the first point, Fennel is simpler than any other lisp I know, beyond "my first interpreter" type Schemes. But you'll find much better learning materials for some other lisps; in particular Racket is exemplary in this regard.
So I would say it comes down to the learning projects you might want to build; this is always the trickiest part of learning any language. If you want to learn by creating a game, Fennel is a great choice. Likewise if you want to extend an existing program that already has Lua support, such as AwesomeWM or Redis. But for most "industrial" type projects that access external APIs or write to existing file formats, you'll have a better time in Racket due to the better library ecosystem.
Actually the best Lisps are those who are actually Lisp (actually implementing the particular syntax and semantics of Lisp) and not a transpiler to another language. This other language leaks on all places.
Fennel is neither a Lisp nor a good learning environment for Lisp. Fennel is actually some kind of Lisp/parentheses-inspired layer on top of Lua. That's nice but not Lisp.
There are a lot of small Lisps which make learning Lisp much more easier. Start with any small Scheme implementation and that's much nearer to Lisp than Fennel will ever be: s-expressions, list processing, evaluator, code as data, macros, data representation, tail/recursion, procedural abstraction, first class functions, lambda calculus, etc etc. There is a lot of excellent material in the Lisp world to teach that. There is even material how to do useful things with that. None of that applies to Fennel. It does not do list processing, its code as data is weak and Lua leaks everywhere.