PAIP: Run Common Lisp in Browser?(github.com)
github.com
PAIP: Run Common Lisp in Browser?
https://github.com/norvig/paip-lisp/issues/10
32 comments
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
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
https://epiphany.pub/@shi-yan/Test-ClojureScript
An Intro: https://epiphany.pub/@shi-yan/introduction
I recently added support for ClojureScript
https://epiphany.pub/@shi-yan/Test-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.
[edit]
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/
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.
[edit]
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/
[deleted]
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.
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.
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) 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).
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.
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.
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.
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?
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?
Or someone could semi-manually create links for all the snippets?
thrax(2)
1: https://common-lisp.net/project/armedbear/
2: https://plasma-umass.org/doppio-demo/
[edit]
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.