Hacker News new | ask | show | jobs
by bakpakin 3050 days ago
Original author here:

The largest reason for use of S exprs is making Meta programming easier. While certain things like arithmetic are more difficult with S-exprs, Macros and DSLs are far easier than with C like syntax. Since Lua is actually only a few steps from something like Guile, it takes very little code to translate a scheme like language to Lua without adding too much runtime overhead. The difficult parts of lisp to implement, namely closures, come for free.

With LuaJIT as good as it is, I would not be surprised if something like this would outperform guile.

2 comments

As a guile fanboy, I doubt outperforming guile is very hard (even though it is fast enough for most uses).

LuaJIT is most certainly faster than guile, but it isn't a very good comparison. Guile is far from the fastest lisp (or even scheme, for that matter), whereas LuaJIT is probably the best JIT on the planet.

That's true. I don't want to criticize Guile or Lisp implementations in general, which have a number of features that Lua can't easily emulate (a numeric tower, true continuations, probably a whole lot more I'm not aware of), but I think Guile and Lua have very similar uses as embedded scripting languages (small, and with fast incremental compilation). Chances are if you using guile you may have considered Lua.

As for use-cases for Fnl, I would say it's more applicable for places where one would use Lua or Guile, rather than something like SBCL or any really fast, compiled Lisp.

Lua makes a pretty good dynamic language target, though, because of the many great implementations and small language spec.

I have often asked myself how LuaJIT can be so fast. It runs laps around every other JITed dynamic language, even fast ones like JS-v8. First of all: Mike Pall, but secondly: lua's semantics must lend itself very well to modern optimization techniques.

LuaJIT is pretty friggin great and I have embedded it a couple of times with great success :)

I do however preferred guile model for multithreading with one instance that an spawn multiple threads, and that can be used safely from multiple threads,but that is just amatter of taste. If you want to spin up multiple instances, guile isn't for you (although you could use multiple threads in a single instance).

So whatever floats your boat :) There was some work implementing lua on the guile VM, which would have been cool.

LuaJIT is probably the best JIT on the planet.

Where can I learn more about how LuaJIT compares to other JITers?

Mike Pall has written about it in some.places online (googling is a good idea), an he has also written quite a lot about LuaJIT and JITs in general on Reddit:

https://www.reddit.com/user/mikemike/comments

LtU has an old, but interesting thread. Can’t tell how much details changed from that time, but since 1Gb limit was removed from LJ recently, it is my The Only Dynamic Language to Consider.

  http://lambda-the-ultimate.org/node/3851
Mike Pall indulges in some (well deserved) gloating far down in the thread:

LuaJIT also does: constant folding, constant propagation, copy propagation, algebraic simplifications, reassociation, common-subexpression elimination, alias analysis, load-forwarding, store-forwarding, dead-store elimination, store sinking, scalar replacement of aggregates, scalar-evolution analysis, narrowing, specialization, loop inversion, dead-code elimination, reverse-linear-scan register allocation with a blended cost-model, register hinting, register renaming, memory operand fusion.

Due to the nature of a trace compiler, it implicitly performs partial and interprocedural variants of all of them. And many traditional optimizations, like straightening or unreachable code elimination are unnecessary.

All of that in 120KB for the VM and 80KB for the JIT compiler. And I didn't need 15 years and a billion dollar budget for that, either.

I'm planning to add value-range propagation, array-bounds-check elimination, escape analysis, allocation sinking, if conversion, hyperblock scheduling and auto-vectorization. Anything I forgot? I'll see what I can do. :-)

Arithmetic isn't more difficult with S-expressions, and in fact complicated arithmetic expressions are easier to format across multiple lines to make their organizations recognizeable. It also naturally supports N-ary operations. For instance (* a b c d) could be a matrix multiplication which chooses the optimal order for the decimation, taking into account all arguments simultaneously.
I like lisp and prefix notation in general, but I definitely still prefer reading large mathematical expressions in infix. Its really just a matter of preference.
Most maths applications written in Lisp use infix/mixfix syntax for the languages they implement, too: Macsyma, Derive, Reduce, Axiom, ...

Implementation of those slightly diverges. Macsyma internally is largely written in Lisp syntax, where for example Reduce is written in RLisp (which is a Lisp written on top of Portable Standard Lisp), which does not use s-expression syntax.