Hacker News new | ask | show | jobs
by tombert 2311 days ago
I really need to learn CL one of these days; I know Clojure reasonably well, and enough Lisp-Flavour-Erlang, Chicken Scheme, and Racket to be dangerous, but for some reason I seem to have completely avoided CL.

Based on the blog posts I've read, it seems like CL occupies the kind of space I want to be in: sort of the halfway point between theoretical and engineering. Is that a fair conclusion to draw?

2 comments

It’s a practical language that sometimes chooses less elegant ways to do things in favor of a complete, robust engineering experience. For instance, the fact defined functions sit in a different namespace than values creates mostly aesthetic ugliness where named functions and named values have different treatments.

    (defun f (x) (* x x))
    (setq g (compose f f))
    (g 5)
This is wrong in Common Lisp on many levels: f must be referred to as #'f, and g cannot be called as such, you must use funcall: (funcall g 5)

These might go against the sensibilities one might have had in learning a Lisp in the first place. But in practice, these don’t stop you from writing solid, readable code.

It won’t feel as “clean” or “academic” as Scheme, but you’ll feel it easier to build large and efficient programs without pulling your hair out.

If I were doing the above a lot, I'd write compose as a macro (or better yet a compiler macro). In that case, the only thing above that needs to be changed is the setq, which would have to be written as

  (setf (fdefinition g) (compose f f))
Still different from Scheme, but some of the differences can be papered over with macros.
Programming with a lot of higher order functions won't feel as clean in Common Lisp due to the #' and funcall.

Basic Lisp programming with lists is a lot cleaner in a Lisp in which the empty list is false, and in which accessing nonexistent parts of a list (including the empty list) is a safe no-op that yields nil.

Ashwin Ram's (cdr (assq key a-list)) almost works in Common Lisp in the form of (cdr (assoc key a-list)). See: https://ashwinram.org/1986/01/28/a-short-ballad-dedicated-to...

Imperative programming is better supported in Common Lisp because the evaluation of the arguments of most forms, including function calls, is ordered, mainly left to right, so side effect embedded in expressions will show stable, portable behavior. Scheme function calls have unspecified evaluation order, much like C. (In Common Lisp, the only unspecified aspect is whether the function cell is sampled before the arguments are evaluated, or just before the function is called. It's extremely rare for the arguments of a function call to be redefining the function cell, needless to say.)

Common Lisp forms return a predictable value. If it doesn't make sense for a form to return a value, its value is not "undefined", but either just nil or else "no values". When a value returns no values, and an attempt is made to use its value anyway, then nil is produced as the value. You will not see some annoying #<undefined> in a Lisp REPL coming from a procedural construct.

I like it. But the really nice thing about lisp is if there's something I dont like, I can just hack the evaluator to fix it.
Just mentioning it for historical reasons (someone correct if this is wrong), Rich Hickey was enlightened by CL after doing lots of Java/C#/C++, after doing much CL he created Clojure.

To answer your question, the JVM has wide acceptance in the industry and a big ecosystem of libraries, from a business and practical point of view, it seems the most adequate choice for a Lisp?

CL compiles down to the metal in most cases (ABCL being a notable exception). I've written device drivers in CL, realtime code in CL, and many CL implementations even allow you to write in assembler. I've done that too, in order to take advantage of SIMD hardware. The above would be -- problematic -- on top of the JVM.

There also might be an issue of speed, since CL is compiled to the metal. Modern JIT JVMs probably have mostly eliminated CL's speed advantage, but I'd still be surprised if some things in SBCL (arguably the best-optimized CL) didn't run faster than in Clojure.

Yeah, that's why the company I work for lets me use Clojure occasionally; we have a metric ton of libraries written in Java and being able to interop with them more-or-less seamlessly is a huge selling point for Clojure.
For Common Lisp one would use ABCL and probably its JSS library for easier Java calls.

https://abcl.org/

Most adequate for what? Peer acceptance?
Are you just purposely ignoring them? adequate for most businesses (the JVM and its ecosystem its going to be accepted way faster than a CL runtime).
I read the comment in its entirety. The adequacy of tools is most often measured by their ability to solve the problems at hand. If the problems are primarily social or legacy, then I could see a completely valid argument that using something JVM-based is most adequate. But one might argue Lisp isn’t adequate at all at that point, and one ought to simply use Java.
Clojure has some other selling points outside of interop though.

For example, Clojure's built-in concurrency primitives like Atoms and Refs are (in my opinion) substantially easier to work with than dealing with "synchronized" or anything like that in Java, and if you're willing to import a library for it, core.async gives you very pleasant Go-like concurrency with channels as well. This allows for a very reactive design that also happens to be safe and relatively easy to debug.

There's also the ability to use macros, which, depending on the use-case, can often replace the need for reflection that you occasionally might have with Java.

Last, it's relatively easy to hook into a running Clojure session with nrepl, meaning that you can use some very-nice runtime debugging and updating without downtime if you're clever.

---------

These features are in most functional languages in some capacity, but most functional languages don't have good interop with Java; the sales pitch for Clojure is comparatively easy: "We should use this language with all these neat features, but where we can use our current stuff just fine".