call-with.cc

State of Scheme to Javascript

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

Examples

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

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

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:


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

(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.