I made some recent updates to
shen-lua, focused on the LuaJIT runtime.
you can also install w/ `luarocks --lua-version=5.1 install shen 0.11.1-1`
I’ve worked on a number of different ports, but I’ve found this one particularly interesting because LuaJIT is such a different host. It has led to a distinctive architecture and set of trade-offs.
First, KLambda is compiled to Lua source. LuaJIT initially runs that code in its VM; when a path becomes “hot,” its tracer records the operations taken and compiles that path to machine code. It optimizes frequently executed paths, rather than simply compiling whole functions because they’ve been called often. The shape of the generated Lua matters, but so does what the Shen program actually does at runtime.
Closures were one of the most interesting parts of the port. Shen’s Prolog compiler and typechecker produce continuation-heavy KLambda. A naïve translation of every freeze into a nested Lua function literal would make some Shen 42 programs exceed LuaJIT’s parser limits. Instead, our compiler hoists continuation bodies into a flat table of functions created at load time. At each freeze site, a small thunk snapshots the free-variable values and refers to the appropriate body. This preserves the delayed computation without nesting another function definition at the use site.
LuaJIT’s FFI offers another way to reduce allocation in the reasoning hot path. When a query takes the native path, the Prolog/type-inference engine stores terms in compact integer arrays and represents continuations with integer handles and a capture buffer, rather than allocating an ordinary Lua closure for every continuation. The compiled-KLambda engine remains available as a fallback. This changes the execution substrate, not Shen’s inference rules.
Other accommodations grew out of the same approach. Large KLambda literal trees can become flat construction blueprints rather than expressions nested beyond LuaJIT’s parser limit. Pure self-tail recursion can become a loop, while list builders shaped like [X | (f ...)] can use tail recursion modulo cons to build long lists without growing the Lua call stack.
@Bruno, as you look at compiling Shen directly to native code, I thought this might be of interest. It’s a rather different way to approach the runtime execution of Shen code.