Sometimes I think Clojure should have been developed on top of the ErlangVM instead of the JVM. I think that the ErlangVM solves a lot better the problems that Clojure is trying to solve. Also, seems like targeting the ErlangVM is an achievable feat, since Elixir in its version 1.3 has proven to be extremely solid.
Crazy idea: if I wanted to implement Clojure on top of the ErlangVM, where should I start?
I think shared memory is foundational to Clojure's approach to concurrency, and that is something the Erlang VM cannot provide. So some main fixtures of Clojure's standard library, like atoms, STM, agents, become either useless or nonsensical.
It's also not clear to me wether the Erlang VM provides what Clojure needs to efficiently implement its user-defined types, protocols, etc
That said, a Clojure-like dialect of lisp built on Erlang is a fine idea and, as others have said, I would probably start by seeing how the Lisp-Flavoured-Erlang (LFE) guys built their lisp.
That's not true. One of the main objectives of Clojure was to be a hosted language. Not just 'language hosted on JVM'. So idea to make it work on top of Erlang VM is perfectly valid and consistent with original design assumptions.
Whether it's as important now or not is a different matter I suppose, with various targets for the language (including other VMs), but I don't think it's in dispute that originally the extensive java ecosystem was core to what clojure was, and was designed to be.
...but hey, don't take my word for it:
The net result is that the prospects for Clojure going forward are
very good. The core model of Clojure has held up well and continues to
appeal - accessible, robust, thread-safe, efficient dynamic functional
programming, on a world-class infrastructure, with a huge set of
libraries. Oh yeah, and it's great fun!
- Rich Hickey, 2008
https://groups.google.com/forum/#!topic/clojure/2CA_H58Cbo0
That might have referred to the CLR and the JVM though since Clojure has targeted both runtimes from the start (although the JVM implementation is leading of course.)
Except then it might not have had as much uptake (tooling, existing Java libraries, installability to various providers and interoperability with existing systems etc.).
Now that Clojure has a varied and excellent set of libraries of its own maybe some of this is less important, but not all (the ability to interact with existing Java systems is still very useful).
To be fair, and I find this to be a bit of a shame, but most of that robustness and ecosystem comes straight from Erlang, which was always solid. Though I do enjoy the consistency that Elixir brings and the improved macros. I'm a Clojure guy, so I also love the protocols.
Just wanted to say that Erlang vanilla is robust and has a great ecosystem. So Elixir builds itself on top of a solid foundation.
I'm curious, what are the practical differences? I know what the theoretical differences are, but do you have any experience with how lisp1 and lisp2 are different in daily use?
I'm afraid I don't have a satisfactory answer for you.
I just prefer to pass around functions/closures as values, and being able to invoke them like any normal function, instead of having to call an helper `apply`/`invoke`/`call` function on them (depending on the language)
That's why I said: "maybe more apt"... if OP doesn't care at all about that difference, and it's not among the details that they'd want to replicate from Clojure, it's perfectly ok to ignore
I never found the funcall argument terribly convincing, because there is no reason it couldn't be much more concise. And it allows you to avoid silly variable names like lst or fst.
In Common lisp to refer to a function as a variable you do (function f) or as (read-table) syntactic sugar #'f. You could easily use destructuring to write HOFs without funcall.
So instead of requiring people to write
(defun bad-map (f list)
"Maps function `f' over `list', inefficiently."
(when list (cons (funcall #'f (first list) (bad-map f (rest list)))))
(bad-map #'- '(1 2 3))
A hypothetical lisp-2 could just as well allow destructuring like this:
(defun bad-map (#'f list)
"Maps function `f' over `list', inefficiently."
(when list (cons (f (first list) (bad-map #'f (rest list)))))
(bad-map #'- '(1 2 3))
The fact that higher order functions stick out a bit by the extra #' is not necessarily a bad thing IMO; it helps when reading unfamiliar code to know immediately what arguments are functions and which ones are just plain objects.
Yeah, braino -- thanks. A custom binding form would be another way to do it, but I'd prefer the pseudo-destructuring -- cleaner and more concise. I'd hope a new lisp-2 dialect would come with better destructuring support for defun and binding forms anyway (destructuring-bind, multiple-value-bind and flet could all be subsumed by let if (values ...) (function ...) where valid left hand patterns).
I just felt that as you can many functions with the same name but with different arities (number of args) at the top-level why shouldn't I be allowed to have it deeper down as well. Also this means that I can only sometimes refer to a function with just its name, when it is at the top-level you need need both name and arity.
This means that Lisp-1 doesn't really fit anyway so why let it limit you?
You might do better to create a Lisp Flavored Haskell (if one hasn't been started already). I'm sure haskeller's would be offended by the idea, but it already uses HAMT.
Crazy idea: if I wanted to implement Clojure on top of the ErlangVM, where should I start?
I would look at retargeting the ClojureScript code generator. Clojure implements a lot of primitives in Java, but ClojureScript is largely written in Clojure and ClojureScript itself so should be easier to port.
Suggestion: Have a look at Lisp Flavoured Erlang [1], a Lisp-2 on top of Erlang/OTP that might be 90% of what you want to achieve. :^) I am sure they are happy for new members of the community!
I think I'd have a look at ClojureScript and/or Clojure CLR (https://github.com/clojure/clojure-clr). The former is Clojure on top of Javascript, the latter Clojure on top of .Net.
It will not be easy, but I'm no expert.
I'm also not sure why you'd really want that? Just to solve the long startup time?
Hmm hmm study the internals of Lumo maybe? Here's a question, would you be able to build non-actor based concurrency primitives like async's go blocks on a actor based erlang framework? (sorta shooting the shit here)
The startup time is of course very low, so that's good.
I think you're underselling the tool for beginners like myself - it's not just a ClojureScript REPL, it's actually an executable which can run node.js scripts written in
clojurescript.
Yeah, we have access to the whole Node.js ecosystem :-) it's also possible to npm install a package and use it from Lumo. The Node require resolution algorithm just works.
Lumo, just like Planck, implements classpath emulation. You can specify colon separated paths to JARs/dirs in which Lumo will resolve requires. Take a look at `lumo -h` for all the available options.
Neat project, but back when I was using Clojure a lot, I lived in Emacs and the time spent for booting up my interactive environment was OK because once booted up, I would work for a long time without restarting from scratch. Same for me now with Emacs+Intero for interactive Haskell development - once everything is loaded, Everything is fast.
This project seems more suited to being able to write fast starting scripts in Clojurscript.
Any canche to see ARM binaries pre built? Would love to run this on raspberry pi / pocket chip. Also planck had io support. Are you planning to add support for io in idiomatic clojure to your project?
I've been using Planck (and Replete for iOS) when I need a fast-starting clj[s] REPL for checking things quickly. What would be the use case for Lumo for me?
The difference is that both Planck and Replete run on JavascriptCore, while Lumo runs on Node.js and V8.
One of the advantages of piggybacking on Node is that we get access to its whole ecosystem for free.
Yes, there's homebrew for Linux -- linuxbrew (http://linuxbrew.sh/). I've found it extremely valuable because where I am, "normal" users aren't allowed root access but can compile things in their home directories. Linuxbrew, being a version of homebrew, makes this much easier than doing it manually.
Every time Clojure comes up I can rely on you to appear and attack something about it (but never the core merits of the language, as far as I can recall.)
Unfortunately, Node.js and V8 seem to be about 2.5X slower than JavaScriptCore for bootstrapped ClojureScript. I haven't found a way around it.
I also don't mean to trick anyone and this is explained in the post.
Mentioning 'fastest' at a time of 3GHZ multicore machines with SSD and a duration of 0.1 seconds is just absurd. That's >100 million instructions just to start a language prompt and evaluating a symbol to itself. The Java version is even more absurd with around 1 billion instructions just to get a REPL...
A shell on a 1 MIPS DEC VAX 11/780 started faster, while the machine had a hundred users.
Crazy idea: if I wanted to implement Clojure on top of the ErlangVM, where should I start?