I have an itch I want to scratch so here we are.
I simply want to take advantage of homoiconicity while working with React. Expressing the ReactDOM as an s-exp list which can be broken apart, recombined, and eval-ed without losing its parse-abilty sounds, well, fun, for lack of a better word or reason. The first step of course becomes, how do I work with Scheme on the frontend...
This idea occurred sometime after I came across RacketScript in one of the usual places I lurk, and that set me down a rabbit hole which brought me to Rackt, React on RacketScript. After a bit of experimentation there, I decided to take a general look at the state of Scheme to JavaScript in 2021.
Scheme -> JS existing options
Going from Scheme to JavaScript is not a new idea, both the Gambit Universal Backend and libraries like Biwascheme are over 10 years old. Some of these solutions, however, are newer, and many are now reaching a level of completeness and maturity where they are quite realistic options for production use-cases. Not only that, but in the ensuing decade the role of javascript as the language of the web has only increased. I encourage everyone interested in Scheme to JavaScript workflows to dig into the available options. Here's a brief overview and links to some of the options that exist that are actively maintained for tackling Scheme and JavaScript workflows. _
Racketscript
Inspired by ClojureScript, Racketscript takes an ideology that Racket !== Racketscript, so it does not try to be Racket in the browser, it tries to blend the syntax and experience of Racket with JavaScript, focusing on comfortable interoperability.
RacketScript does disclaim: "RacketScript is work-in-progress and is not mature and stable. Several Racket features and libraries are not yet implemented (eg. number pyramid, contracts, proper tail calls, continuations). There are also quite a few missing primitive functions. That said, we encourage experimentation, user feedback, discussions, bug reports and pull requests."
Notable Feature
- It leans into modern web-tooling, fitting nicely into projects that are already using
npm
/yarn
.
Examples
- RacketScript Playground
- Rackt Demo
- Rackt is thin react wrapper on RacketScript. _
Bigloo / Hop
This one is wild and awesome. I'm a huge fan of Bigloo and their take on this is incredibly unique. Hop is an application built on top of Bigloo, it is a JavaScript engine. That is, Hop is more akin to Google's V8 engine AND node, than it is to simply node. Hop lets you blend server-side and client-side code, writing Bigloo Scheme or JavaScript with a beautiful API for working with JS types in scheme and vice-versa. It's worth checking out, but compatibility with existing toolchains and libaries is not a priority so it didn't make it the right option for this. (Though it includes its own reactive programming paradigm.)
Examples
- I created a very simple blog framework in bigloo / hop that uses their MySql connection, embeds an editor and leans into their auth model. _
Biwascheme
BiwaScheme is an interpreter written in Javascript, it borrows from its host language, meaning strings are mutable and numbers are just numbers (as opposed to floats and integers). The homepage showcases several demos of biwascheme in action. _
LIPS
LIPS and Biwa are both schemes implemented in JavaScript. They have slightly different ideologies with LIPS focusing more on easy interoperability with the host language. _
Spock (Chicken)
Unlike RacketScript, Spock does try to match Chicken feature-for-feature, but similarly disclaims: "This extension is still in a very early state and is likely to contain numerous bugs.[...] the compilation strategy used stresses JavaScript implementations in unusual ways and the results indicate that many JavaScript engines seem to have quite serious limitations regarding static function nesting and closure performance." Regardless, its impressive in how it tackles the challenge.
Examples
- this reddit post by u/amirouche showcases both a hosted example and the source code for it. _
Gambit Universal Backend
Gambit is best known as a Scheme -> C compiler, but that is not all its capable of; different backends can be targeted, including Python and JavaScript. Unfortunately, it's not very well documented on the main page, but the interactive demo at try.gambitscheme.org certainly caught my interest and there is plenty of information, examples, and conversations around it on their gitter channel to get started. It seemed to be the most mature, complete and performant scheme-in-js. Gambit's maintainer Marc Feeley also has helped author the next entry, Ribbit Scheme. Ribbit has fewer features than Gambit, as expected when comparing a 4k runtime to a 700k runtime respectively. These Gambit features include:
- R7RS conformance including R7RS modules
- a JavaScript FFI that supports asynchronous calls between JS and Scheme
- a thread system built on top of first-class continuations
- serializable closures and continuations allowing task migration
- access to files on the server using Scheme file I/O
- Scheme to JS compilation for fast execution
Ribbit Scheme
The Ribbit compiler is written in Scheme and the Ribbit VM comes in C, Python, and Scheme flavors in addition to JavaScript. The 4k runtime packs in a wealth of features including support for tail-calls, continuations, a REPL, AOT and incremental compilers. As mentioned, Ribbit has fewer features than Gambit but also different goals.
Resources
- Demo: https://udem-dlteam.github.io/ribbit/repl-max-tc.html
- Repo: https://github.com/udem-dlteam/ribbit https://udem-dlteam.github.io/ribbit/repl-max-tc.html
- Paper: http://www.iro.umontreal.ca/~feeley/papers/YvonFeeleyVMIL21.pdf https://udem-dlteam.github.io/ribbit/repl-max-tc.html
(credit to Marc Feeley for the Gambit feature list and the above listing of Ribbit features)
Chibi
The chibi repo can be cloned, and make js
will create an Emscripten build: chibi.js
. It also provides an example of its usage. Emscripten allows some C/C++ code to be compiled for the browser and thus this same approach can be taken for other schemes that compile on LLVM toolchain. The same approach can be seen taken here with Gambit: http://feeley.github.io/gambit-in-the-browser/.
wasamasa
on the scheme discord also brought to my attention the following archive link with A LOT MORE schemes on the web: https://web.archive.org/web/20200405073418/http://ceaude.twoticketsplease.de/js-lisps.html. I'd like to thank inglrs
for bringing the chibi build to my attention. Marc Feeley brought ribbit to my attention and surfaced several gambit feetures worth pointing out.
Let me know if I missed any!
As for the proof of concepts I'm curious about, after researching and experimenting for a few days I decided it would be a fun exercise to implement something like Rackt in Gambit.