Hacker News new | past | comments | ask | show | jobs | submit login
PAIP: Run Common Lisp in Browser? (github.com)
68 points by register 64 days ago | hide | past | web | favorite | 29 comments

Something not mentioned here is that ABCL[1] will run in DoppioJVM[2], but the startup time is on the order of an hour last time I tried, so it's not yet practical.

1: https://common-lisp.net/project/armedbear/

2: https://plasma-umass.org/doppio-demo/


With the doppio demo linked, I get a REPL in about 2 minutes on chromium and under 5 on firefox. That's a huge improvement since I last tried.

Performance is not great though; I ran the gabriel "boyer" test and it was 0.288 second on openjdk 1.8 and 63 seconds on Doppio in chromium.

In my machine it took seconds.

Which version of ABCL were you running? I tested with the 1.5.0 binary jar.

I am working on a CL for JS that I will likely share at some point. I post updates about it occasionally to Mastodon [1] if anyone is interested in following my progress. I'm also happy to discuss rationale, design, and implementation -- it's been really fun to work on.

1. https://mytoot.net/@alandipert/103120653862853368

I'm making a programmable blog, aiming to become a platform for interactive e-textbooks. (thinking Medium.com + Jupyter Notebook)

I recently added support for ClojureScript


An Intro: https://epiphany.pub/@shi-yan/introduction

I wonder why Clojurescript succeeded where Common Lisp hasn’t: compiling a lisp to javascript. Is Common Lisp particularly tricky in some way that Clojure isn’t?

Clojure is unique in that its definition is contingent upon a host VM (CLR, JVM originally, JS as well now). It's not hard to come up with code that will work in clojurescript but not Clojure/clr or clojure/jvm.

For client-side I tend to use Parenscript[1] which doesn't particularly try too hard to look like Common Lisp, but does allow for macros to be written in Common Lisp. Since it's not trying too hard to look like Common Lisp, javascript interop is dead-simple, but since the metaprogramming is in Common Lisp, I find it to be a good middle-ground.


If it's not clear, parenscript has design requirements that make it unable to ever be a full common-lisp on its own; the desire is that you could emit a webpage where e.g. the onclick property is generated from parenscript, and it will work, without any other javascript libraries being loaded. This obviously means you, e.g. can't have a lisp numeric tower available.

1: https://common-lisp.net/project/parenscript/

a) Common lisp was already in undead state when Javascript became big. Semi-dead languages as a rule have worse tooling for "new" stuff.

b) Clojure didn't really fully succeed, there were annoying differences between Clojure and Clojurescript last time I looked. There are compilers for incomplete subsets of CL to JS as well, although presumably much worse ones.

c) There's some stuff in Common Lisp that's quite hard to do efficiently on top of most existing language runtimes. For example resumable exceptions and lua/CL-style optional multiple return values. In assembler or without concern for efficiency the last one is trivial, otherwise, not so much.

d) Clojurescript could bootstrap existing fancy JVM platform stuff (closure compiler) to do quite a lot of heavy lifting.

I like Clojure, but sometimes I dislike it's so heavily tied to the JVM and/or purely functional.

I think a modern multiparadigm Lisp on LLVM would be great. Perhaps that's Julia, though.

B & C are good points, but...

A) Writing a new Common Lisp implementation is a major undertaking, but a new implementation was creates specifically for C++ interop[1], and that implementation is certainly post javascript being big.

D) Anything targeting JS can run the output through closure; I've done so with Parenscript, for example.

1: https://github.com/clasp-developers/clasp

A) I'm well aware of clasp, and its a cool project (and post javascript, as well) but it's hardly anywhere near production quality right now (unlike say, clojurescript). So I don't think it's a counters my argument about the CL ecosystem (I'm sceptical that it would make much of a dent even if it becomes a technical success beyond Dr Meister's wildest dreams).

D) Of course, but if you require some additional JVM based tooling for a JVM language like clojure, you lose 0% of your potential audience and introduce no additional friction, which is not at all the case for CL (nor would it be for, say C++ or Lua).

Related to a), Clojure is just more popular than CL, and has a lot of momentum pushing it into the browser.

I'm aware of CL-like lisps that compile to JavaScript which are likewise incomplete and incompatible.

Oh look, a comment in this submission Github's item points to JSCL, for example.

Clojure is far more popular than Common Lisp, and it attracts people who like Lisp and interopability, not just Lisp, so its ecosystem is more developed.

Common Lisp traditionally favors other forms of interoperability: with Assembler, C, C++, Objective-C, UNIX/POSIX, etc... For example one prefers to directly call old-fashioned GTK+, Cocoa or Windows - instead of calling via a Java UI layer or a Javascript library. Common Lisp has interoperability with the JVM in various forms (from FFIs to ABCL, a Common Lisp on JVM implementation), but it's not a popular choice.

There are several CL implementations with deep C integration, for example by compilation to C. CLASP has deep C++ and LLVM integration. Some implementation can create shared libraries which are being loaded from other programs.

CLASP: https://www.youtube.com/watch?v=8X69_42Mj-g

It's possible to bring Common Lisp on top of runtimes like the JVM or Javascript - but there is some larger mismatch, because Common Lisp (different from Clojure) a platform independent full programming language. For example Common Lisp specifies a numeric tower with bignums, some float types, complex numbers and rational numbers. JavaScript internally does only offer floats. Common Lisp also specifies its own object system, which does not map well on top of the JVM (single inheritance, non-dynamic) or JavaScript.

This topic comes around every couple of months, here and elsewhere.

I tried to run some of my CL stuff in JSCL, but the browser just froze, so I quickly gave up on that. Guess it can't handle more complex stuff.

I wonder if someone ever tried to compile a C-based CL implementation (like sbcl) to WebAssembly (i.e. using emscripten) ? I'd be surprised if nobody ever tried that, but I never read any reports regarding success or failure.

To answer Peter’s original question, cl-jupyter works fine, at least when I used it in 2018.

I would like to implement a web front end or a Common Lisp LSP server based on swank/slynk if I had time...

Does anyone know about prior works I could potentially contribute to?

The thought that immediately springs to mind is bootstrapping CL on top of parenscript.

...and https://github.com/jscl-project/jscl/blob/master/src/compile... makes it look like that's almost what's going on here, but not quite.

clasp (LLVM frontend for Common Lisp) to Emscripten would be interesting.

Does LLVM self-host in emscripten yet? It didn't last time I checked.

It doesn't, that's a shame. It would definitely have to be a custom fork of either Clasp or Emscripten anyway because CL's "memory dump" way of creating executables would be too cumbersome to run in browsers. Someone might as well make a CL -> WASM compiler directly--in CL so that it could be more easily self-hosted.

I did a quick scan of the WASM standard, and there don't appear to be any instructions that let you e.g. add new functions, so it's not even clear to me how you would call WASM that you had newly generated.

could a bit of JS code in the page upload the snippet to tio.run or repl.it for execution?

Or someone could semi-manually create links for all the snippets?


There are a handful of Scheme implementations in the browser. Also ClojureScript. The problem with ANSI Common Lisp is it's gigantic. It is almost as big as C++ and not at all trivial to implement. It doesn't help that most Lispers are either dead or only use the web via w3m in Emacs.

I never quite understand this though.. because everything that I've seen about scheme/lisps is that it's a simple modular syntax, self hosting, etc. is it the runtime that is gigantic? Or its std lib?

I'm not sure either honestly. I've used Lisp a lot but never looked at the internals. I can see why it would be hard to implement. It has an object model unlike any other language (CLOS). It's memory model is equally baroque. A lot of the complexity comes from needing to be both interpreted and compiled at the same time, at all times, which is still unique today. A lot of completely arbitrary things like the infamous LOOP macro are in the standard library.

> It has an object model unlike any other language (CLOS).

object models differ widely. Compare Smalltalk, Java and C++.

CLOS had influence on a bunch not so mainstream languages: Perl5 (Moose), Perl6, Julia, R, Scheme (TinyCLOS and similar) ... and a bunch of extensions to C, Java and other languages.

There are some difficulties to make CLOS fast on top of, say, the JVM. One can't map the full CLOS directly on top of Java objects, since they lack some features like multiple inheritance, direct class updates, etc. So there is a layer of mapping necessary - which is possible -> ABCL. But it's not as fast as a direct implementation.

> A lot of the complexity comes from needing to be both interpreted and compiled at the same time

Not sure what you mean by 'interpreted', but there is no requirement to support both. SBCL for example and no Lisp interpreter for many years. It now has one, but it's not used much. Clozure CL also has no interpreter.

Btw., EVAL is no interface to an interpreter. SBCL would compile the code at runtime.

> A lot of completely arbitrary things like the infamous LOOP macro are in the standard library.

It's not arbitrary. It's a standardized iteration facility. LOOP actually does not make implementations difficult, since there are ready-made LOOP implementations which can be just loaded into Common Lisp.

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact