The extra features that QMK has and Menelaus doesn't aren't really all that appealing to me to begin with.
3,634 karma · joined February 21, 2007
Coding in Clojure, Fennel, and Lua.
The extra features that QMK has and Menelaus doesn't aren't really all that appealing to me to begin with.
That article goes into more background but it's based on a much earlier version of the firmware; as of last week I've gotten it to be feature-complete and stable, and I've been using it as my daily driver.
I have been meaning to follow up the article with a part 3 that covers the rest of the features, but in the mean time I have added copious comments to the source link above such that it covers almost everything you need to know. (This is probably the most heavily-commented piece of code I've ever written with a 1:1 code:comments ratio.)
I have also been working on a GUI configuration tool in Racket that emits Microscheme source files you can compile and upload to your keyboard: https://git.sr.ht/~technomancy/menelaus/tree/master/gui.rkt https://p.hagelb.org/menelaus.png
If you've looked at building an Atreus before but gotten intimidated by the soldering, we have a kickstarter for a non-DIY version that's significantly cheaper than the kit: https://www.kickstarter.com/projects/keyboardio/atreus
I'm working on a similar programmatic definition of the Atreus here: https://icosahedron.website/@technomancy/101809590723531930
It's still a work-in-progress, but being able to tweak the input parameters and recompile to get the board regenerated is really handy! The circuit board already uses programmatic alignment for placing the switches and diodes: https://github.com/technomancy/atreus/blob/master/atreus.rkt
Here's an instance where someone damaged their kit's microcontroller and was walked thru the repair process: https://old.reddit.com/r/MechanicalKeyboards/comments/5clvio...
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.
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
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.
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.
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.
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.
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.
On a related note, how is "halt all execution and scheduled future execution of scripts in the current tab" not a solved problem for mainstream browsers? Or maybe it is and somehow I missed it?
My take is that the biggest difference is not in the language but the runtime. Nearly all the things that Racket lacks (except world-class GC and JIT compilation) can be added in after the fact due to its massive flexibility; Racket is a natural choice when you want a lisp but can't afford the memory or launch time overhead of the JVM. Unfortunately the things that Racket does well typically cannot be retrofitted onto Clojure due to its sloppy semantics around nil, but maybe Clojure's port of Racket's contracts system will change the balance there.
In practice you don't replace TCO with loop/recur; you replace it with lazy sequences. They both solve the "how to work on unbounded data while consuming bounded memory" problem even though at first glance loop/recur seems more similar.
Most people who complain about not having TCO have not fully wrapped their heads around lazy sequences.
I mean, it's generally agreed that English as a language has accrued so much historical baggage that it's shed any elegance or coherence it may or may not have once had. It would honestly be surprising to me if the same thing didn't happen to musical language.
The whole point of benefiting from immutable data structures is their ubiquity. If they're something you reach for only when you personally decide you need them, they're unlikely to work well with 3rd-party code; you will have to do a lot more digging to understand how the code you're writing will behave in a concurrent context vs having it be obvious. Making it opt-in is almost making it pointless, unless you never use 3rd-party code.