Live data from Hacker News

Differences with other Lisps

clojure.org

61–70 of 108 posts

Re: Differences with other Lisps

#61
post #58

Earlier quoted context omitted.

> I just with there was a Lisp like it that didn't run on the JVM. There are a few, with varying degrees of distance from the JVM and varying degrees of similarity to Clojure. - There's ClojureScript, which is Clojure transpiled to JavaScript. - See also Lumo ( ) and Planck ( ) - There's Babashka ( https://github.com/babashka/babashka ), which is a natively-compiled Clojure interpreter, implemented with the Small Clo…

I'm surprised to see no Clojure built on Go. Is there a technical reason why this wouldn't be a good idea?

> - There's Joker (https://github.com/candid82/joker) with a similar mission to Babashka, but commonly used as a linter.

Joker is a Clojure interpreter, mostly used as a linter in the community but can be used as a runtime as well.

Re: Differences with other Lisps

#62
post #58

Earlier quoted context omitted.

I'm surprised to see no Clojure built on Go. Is there a technical reason why this wouldn't be a good idea?

> - There's Joker ( https://github.com/candid82/joker ) with a similar mission to Babashka, but commonly used as a linter. Joker is a Clojure interpreter, mostly used as a linter in the community but can be used as a runtime as well.

By "built on Go" I meant like Java: you can use Go libraries and compile it as you would compile Go code, to a single binary.

Re: Differences with other Lisps

#63
post #49

The bigger picture: Clojure was designed with no backwar(d/t)s compatibility. https://clojure.org/about/rationale#_lisp_is_a_good_thing > Clojure is a Lisp not constrained by backwards compatibility Which means that basically no (!) Lisp software from the past ran in Clojure and trying to make it results in a re-implementation and re-architecture of that software.

> Clojure was designed with no backwar(d/t)s compatibility

Correction: Clojure was designed with no backwards compatibility with previous lisps

Clojure puts a huge focus on being backwards compatible within it's own ecosystem. I've used libraries that haven't been updated in ages (think Clojure 1.3) but still works the same way as they did back then. This is also reflected in the community where libraries are very careful of breaking the public API, often creating new libraries under new names if there are breaking changes.

Re: Differences with other Lisps

#64
post #62

Earlier quoted context omitted.

> - There's Joker ( https://github.com/candid82/joker ) with a similar mission to Babashka, but commonly used as a linter. Joker is a Clojure interpreter, mostly used as a linter in the community but can be used as a runtime as well.

By "built on Go" I meant like Java: you can use Go libraries and compile it as you would compile Go code, to a single binary.

I see! "Built on X" would usually refer to what language something is built in, while what you're talking about is "interoperability" with the host language.

But yeah, unfortunately Joker doesn't do interop, which is sad because it's one of the coolest features of the Clojure language.

Re: Differences with other Lisps

#65

I've been messing with Clojure/ClojureScript for a few years having previously had zero Lisp experience. Overall, I think Clojure does a good job of being both practical and lispy. It's a language that is for building real things. I've been focusing on ClojureScript ( https://clojurescript.org/ ) as you get the benefit of interoperating with the Javascript ecosystem. The fact that there's a strong community around bo…

I've read that Clojure(Script) has a great REPL experience. Even when using VSCode, can one use the REPL easily?

Re: Differences with other Lisps

#66

I've been messing with Clojure/ClojureScript for a few years having previously had zero Lisp experience. Overall, I think Clojure does a good job of being both practical and lispy. It's a language that is for building real things. I've been focusing on ClojureScript ( https://clojurescript.org/ ) as you get the benefit of interoperating with the Javascript ecosystem. The fact that there's a strong community around bo…

> Overall, I think Clojure does a good job of being both practical and lispy. It's a language that is for building real things. As opposed to? Common Lisp and Emacs Lisp are both highly practical. Scheme you might call more academic, but that's not really what people think of when they say "Lisp".

CL is not really highly practical. The stdlib is not very coherent and lackluster in general (do I really need to import external code to split a string?), the commonly accepted package manager is in an eternal beta limbo, the whole QL/ASDF/... thing is clumsy, parallel/concurrent libraries are very low-level, etc.

Now SBCL in itself is rock-solid and a fantastic experience when used with emacs, but the CL ecosystem is insufficient to qualify as “highly practical”.

IMHO, the most practical lispy language is Racket: tight language, excellent stdlib, easy to package and deploy, and a development experience that worse than CL but good enough.

Re: Differences with other Lisps

#67
post #66

Earlier quoted context omitted.

> Overall, I think Clojure does a good job of being both practical and lispy. It's a language that is for building real things. As opposed to? Common Lisp and Emacs Lisp are both highly practical. Scheme you might call more academic, but that's not really what people think of when they say "Lisp".

CL is not really highly practical. The stdlib is not very coherent and lackluster in general (do I really need to import external code to split a string?), the commonly accepted package manager is in an eternal beta limbo, the whole QL/ASDF/... thing is clumsy, parallel/concurrent libraries are very low-level, etc. Now SBCL in itself is rock-solid and a fantastic experience when used with emacs, but the CL ecosystem…

The commercial Common Lisp I use, also has large amounts of extensions to CL. Including a function to split sequences/strings, parallel and concurrent extensions, ... ;-) It's actually the same commercial Common Lisp which Rich Hickey used years ago to write his first Lisp programs and where he developed his first ideas for Clojure.

Re: Differences with other Lisps

#68
post #58

Earlier quoted context omitted.

> I just with there was a Lisp like it that didn't run on the JVM. There are a few, with varying degrees of distance from the JVM and varying degrees of similarity to Clojure. - There's ClojureScript, which is Clojure transpiled to JavaScript. - See also Lumo ( ) and Planck ( ) - There's Babashka ( https://github.com/babashka/babashka ), which is a natively-compiled Clojure interpreter, implemented with the Small Clo…

I'm surprised to see no Clojure built on Go. Is there a technical reason why this wouldn't be a good idea?

Is this surprising? I don't see an ecosystem of languages targeting the Go runtime, in contrast to the JVM, Javascript, Erlang, MS CLR...

I don't think this is necessarily a matter of popularity or maturity. I don't know of languages that compile to Python bytecode, either. In Python's case I suspect the VM is so optimized for Python that it makes an inflexible target for other languages: I don't know enough about this subject to say whether that's the case for Go as well.

Re: Differences with other Lisps

#69
post #33

Maybe a more seasoned LISP-`aterian` can answer me ? I'm in the process of learning ClojureScript - real fun so far. I have of course also looked at other LISPs and have noticed that in CJS the use of square brackets[] for vectors, let and `function params` (defn myfunc [] (let [some-var (:some-key some-state)]) (.log js/console some-var) ) I almost never see square brackets in other LISPs (yes I'm truly a beginner a…

The reality is that just about every single lisper will insist how they don't see the parenthesis and they are not a problem, and just about every single lisp has some ugly ad hoc hacks to reduce their clutter. They just differ somewhat between lisps. Scheme (and descendants like racket) went so far as to make [] and () interchangeable. So you will in fact see brackets in some scheme most e.g. (let ([a 1] [b 2]) ...)…

There have been LISP dialects where a single closing square bracket was used to close all the remaining open round parentheses.

Re: Differences with other Lisps

#70
post #45

Earlier quoted context omitted.

Using [] for syntax like Clojure does is kind of weird and not too consistent IMO. As for data structures, CL has vectors (and more complex arrays), with #() as a literal syntax or my preference just the function (vector ...). But beyond that, CL is just not nearly as opinionated as other languages. You are free to define a function named [] as a wrapper around aref, if you wanted to write things like ([] array index…

> Using [] for syntax like Clojure does is kind of weird and not too consistent IMO Actually, it’s very consistent. Round parentheses are used for syntax where the first element is a “command” that will be evaluated, and square brackets are used for list of things where the first element is not “special”. For example, in `(let [x 0 y 1] (conj [2 y] x))` - `let` and `conj` are commands that will be evaluated, and the…

Neat, I don't remember hearing about the "command" justification before. I suppose this is a rationale behind e.g. the 'ns macro separating its command-keywords that map to functions with parens? Still, I always thought the full syntax of 'ns and the individual things inside of it was a bit wild. Thank goodness for Slamhound...

Like, take (import [package thing-in-package other-thing-in-package]) -- the first element is "special" in how the rest are interpreted. 'gen-class takes :methods as [[method-name [arg-types] return-type]] while 'letfn separates the inner functions with ()s. Multi-arity functions use () as the separator, too. But why not []? Is the [foo] arglist^H^H^H^Hvector in ([foo] body) in (defn blah ([] body) ([foo] body) ...) meant to be a "command"? Or the name of the local function in 'letfn a command?

Using "nothing"/implicit argument pairs like in 'case/'cond/'extend-protocol/... instead of wrapping them in a vector like 'let can feel inconsistent, but it's understandably popular even if it can make things harder to edit or easier to introduce bugs. Writing things that way is a common introduction-to-macros for CL, too, and pair-lists are often used for literal maps rather than importing something that makes a hash table. Looking at Clojure's 'case again though I guess you were mentioning its ability to match multiple values with (x y z)? Ok, but it seems to me just a consequence of porting behavior from CL, not a big deal.

It still strikes me as weird that Clojure introduced nice data literal sugar, except I can't be sure that when I see it that it's always a data literal. When I see [], it might be a literal vector with every element evaluated, or it might be embedded in a context with complex syntax and effects. Like sometimes it's just a sequence of binding forms such as in simple function arguments, sometimes there's an implicit pairwise association going on like in 'let, sometimes the first element determines how the rest are interpreted, or there might be keywords thrown in the middle that determine the rest. This problem extends to some popular libraries, too (e.g. Reagent's syntax for components always bugged me). In practice it's not a huge deal, sure, and I liked it for a while, then I got used to CL and prefer its idioms.

All this isn't to say that CL is a paragon of consistency (see kludges: https://stevelosh.com/static/images/blog/2018/07/lisp-kludge...) and when it comes to syntax you still have to deal with similar issues of interpretation (CL lambda-lists have some rich behavior, the loop macro has many features, format strings too, etc. not to mention stuff in libraries, and custom reader macros doing whatever), but I am saying that I don't think Clojure's introduction of [] and {} for core syntax on top of their roles as data literals actually made things any better.

Post reply on HN