To make a statement about Common Lisp from simple tutorial code is a bit much.
If one looks at music software in Common Lisp, the code is on a higher level than building lists like that.
> Secondly, this code tries to handle lists in the classic Lisp way, with recursion, and that's not what you typically do in Clojure.
Neither is it done in Common Lisp.
> Those 7 lines of Common Lisp compress to 2 lines of Clojure
The actual difference is that Common Lisp uses LOOP and not FOR, and that LOOP needs two nested LOOP forms:
CL-USER 11 > (defun build (list1 list2)
(loop for e1 in list1 append
(loop for e2 in list2 collect (list e1 e2))))
BUILD
CL-USER 12 > (build '(1 2) '(a b))
((1 A) (1 B) (2 A) (2 B))
Two iteration forms in a LOOP don't nest, but provide iteration bindings similar to LET* and LET:
(loop for i in '(1 2 3) for j = (expt i 2) collect (list i j))
and
(loop for i in '(1 2 3) and j in '(1 4 9) collect (list i j))
Common Lisp's ITERATE macro also needs nested forms, but slightly improved over LOOP:
ITER-USER 26 > (iterate outer (for i in '(1 2))
(iterate (for j in '(a b))
(in outer (collect (list i j)))))
((1 A) (1 B) (2 A) (2 B))
The author of Clojure knows these differences very well, since he was a heavy Common Lisp user for a few years.
> But, at the same time, if you're looking to translate stuff from other Lisps into Clojure, it's not going to be just copying and pasting. Beyond inconsequential, dialect-level differences like defn vs. defun, there are deeper differences which steepen the learning curve a little.
That's true. Clojure is not a Lisp, but partially derived from it, with many other influences from Haskell and other languages. It's mostly incompatible to Lisp: software can't be shared or copied, it needs to be complete rewritten. Thus basic Lisp literature is only of use when it's about features which got copied. For example the book 'On Lisp' might help to understand macros in Lisp and Clojure, whereas books like 'Practical Common Lisp' or Norvig's PAIP aren't very useful for Clojure programmers.
I think the problem is that people seem to equate "Lisp" to "Common Lisp". Clojure is a Lisp, but Clojure is not Common Lisp.
LISP appeared in the late 50's/early 60's. Common Lisp only appeared in the early-to-mid 80's. There were many other lisps in between and many since. Common Lisp is only one of many dialects of Lisp. Clojure is another.
(Not saying that this is what lispm did in this case, (s)he seems to know a lot about lisp; rather this is a common confusion I've seen)
Common Lisp, though, is the lineal descendant of the original LISP, so a case needs to be made for anything else like Scheme and Clojure that claim to be Lisps. I guess I'm saying it's a debatable point.
I'm not sure calling "Clojure not a lisp, but partially derived from it" really makes sense.
That code from other lisp implementations needs rewritten to be ported, is really not that much different from how many other lisp implementations were to each other.
CL and Scheme did a lot to unify things, such that any scheme should run another scheme's code. Same for any CL implementation. But, for example, running emacs lisp in any other lisp just isn't going to work.
Fair. There have been, and always will be lisps that can be copy pasted between each other. Just as you can get some implementations of programs in some assemblies that work between assemblies.
That does not say anything about whether or not a language is an assembly. Just as this says nothing about whether a language is a lisp.
You're bunching Clojure in with several languages that have strayed far further from Lisp. Clojure was designed specifically with the intent of being a dialect of Lisp, which means it's explicitly not in its own language family or in any other language family than Lisp.
> Clojure was designed specifically with the intent of being a dialect of Lisp
The result of that design is that Clojure shares literally zero lines of code with other Lisps: Autolisp, ISLisp, Emacs Lisp, Standard Lisp, Common Lisp. Many basic concepts are absent, renamed or redesigned ('Atom', 'Linked List', ...). Clojure is fully incompatible to any other language with Lisp in its name. Programs have to be re-architectured, because the concepts are different: no TCO, but 'functional', different approach about side effects (-> avoid), lazy persistent datastructure at its core, different idea of OOP (-> avoid), Lisp infrastructure (-> avoid), ...
There is no software I know of, which is shared. The number of tools shared is 'one': GNU Emacs. It's a different community with different goals, different software, different applications, different libraries.
Just think of it: zero lines of code is shared.
My problem with that broader idea of 'Lisp': it is fully vague and it has no practical implications. Sometimes it's only a marketing slogan. It has the same vague meaning like 'object-oriented' or 'Functional'. There is no consensus what OOP in a broad sense means and how it should be defined. 'Lisp' is just as useless.
It does not mean that Clojure is useless or worse than Lisp. Totally not. Clojure has new ideas on data structures put to work and enabled some very productive people enjoying their tools. They are doing wonderful stuff.
Neither does Emacs Lisp nor ABCL. Yet they are Lisps by your definition.
> different approach about side effects (-> avoid)
Though not precluded. You can write Clojure with side-effects, but to do so you need to be explicit about it.
> different idea of OOP (-> avoid)
Which says nothing about the language or its Lisp-nature. Clojure has generic dispatch with multimethods, supporting runtime polymorphism. As you say later, "OOP" is meaningless since it's definition is vague, so using this as a reason for Clojure to not be a Lisp is odd.
> Just think of it: zero lines of code is shared.
Are saying that a lisp is only a 'Lisp' if you can freely share code between them? Without modification? If the names used for functions aren't the same, then that disqualifies it from being a Lisp?
Your position seems to be that unless the lisp is a direct descendant of Lisp 1.5 then it cannot be called a Lisp. In addition to Clojure, this disqualifies Scheme (and its dialects.)
Different Lisps (by your definition) take different approaches to things like namespace separation (Lisp-1 vs. Lisp-2) and scope (dynamic vs. lexical). These differences can be subtle and lead to hard to find bugs when sharing code.
> My problem with that broader idea of 'Lisp': it is fully vague and it has no practical implications.
Yet you have put a stake in the ground and defined the broad idea of 'Lisp' as an entity that shares its roots with the ideas in MacLisp.
> The result of that design is that Clojure shares literally zero lines of code with other Lisps: Autolisp, ISLisp, Emacs Lisp, Standard Lisp, Common Lisp. Many basic concepts are absent, renamed or redesigned ('Atom', 'Linked List', ...). Clojure is fully incompatible to any other language with Lisp in its name.
> Programs have to be re-architectured, because the concepts are different:
"Re-architectured" can be read in a multitude of ways. Changing a few datatypes because Clojure prefers vectors instead of lists, etc., feels like it falls well below the bar for "re-architectured".
> no TCO, but 'functional'
This would hold weight if CL mandated TCO, but it doesn't.
With this in mind, I'd like to examine a few of your points from a different angle:
Racket:
- Basic concepts are the same, (atom, linked lists, '...')
- Restructuring not really needed (up for debate, depends entirely on your prefered initial design choices in either language. Racket isn't that opinionated.)
- Tail call optimization required as per Scheme standard, so is present. Note that this is not actually something Lisp mandates.
- Doesn't 'care' about side effects, community is pragmatic and will generally advise you to do whatever is practical
- Has an object oriented sub-language with message passing and so on
There are a lot of points here that, according to you, makes Racket essentially a Lisp, even your non-point about TCO. I'm curious to know what you feel about people saying Scheme is a Lisp, considering the above.
The whole debate of "Is X (a) Lisp?" reminds me of nationality debates that essentially boil down to some people saying blood is more important than culture. You seem to be taking both sides, however; arguing culture and blood (source code). You cherry pick the cultural differences like most people standing on one side of the nationality debate would and argue that just those specific differences are the most important.
That's the thing, though; Swedish people could argue however much they want that they're very different from Norwegian people. To the rest of the world, though, they're essentially the same. Especially when you start comparing them to people from Peru, Venezuela, South Africa, and so on. When you're in the bubble the very small differences are much bigger to you, but if you zoom out to get some perspective these differences are much smaller than the commonalities.
Yes. I was asking you, because you have ideas of what makes a Lisp a Lisp. I've given you several reasons that by your own admission were important for a Lisp being a Lisp and I'm wondering, considering what you've said was important, if you think Racket is a Lisp.
In practical terms Racket is not a Lisp. There are large areas of overlap. The people behind Racket steer the language further away - which is nothing bad, just an observation... there are lots of new features in Racket, which are not in Lisp.
I find that interesting, considering that most of the points you raised about Clojure not being a Lisp would indicate that you think Racket is a Lisp.
You've also been nothing but vague in terms of what makes Racket not a Lisp, which is ironic considering your previous argument that we should have more clearly defined requirements for what makes a Lisp, but I'm beginning to think that this was mostly hot air.
I think you've mostly proven that the 'vague' definition serves a much more practical purpose than your seemingly arbitrary distinction between these languages, and it will continue to do so, as it implies far more than you've displayed in this thread.
> You've also been nothing but vague in terms of what makes Racket not a Lisp
True, and I have to apologize for that. But I don't have the time, nor the priority to go into full detail. The main points are: different community, different goals, almost zero code sharing, different technical solutions, different literature, ... The differences are technical and social. Each of the points would need more explanation, for which I don't have the time.
For me 'Lisp' is something practical. I have a bunch of non-trivial code -> can I compile/load it? Can I port it easily? Are there people who would be interested to share? What are they using? Can I work with them?
Example:
Macsyma is an old Lisp program. New Lisp dialects appeared. Macsyma was ported to them: Maclisp, Franz Lisp, NIL (New Implementation of Lisp), Lisp Machine Lisp, VaxLisp, Common Lisp...
This software can't be ported to Clojure or Racket, without fully re-architecting the software, and I'm only thinking about the basic Macsyma, without GUI or other system dependent parts.
> that the 'vague' definition serves a much more practical purpose
which one? to confuse people? To raise expectations of collaboration in a community, which are then not fulfilled?
It's true that it is more difficult to port from Common Lisp or other Lisp-2 dialects to Scheme, Racket, or Clojure (which are Lisp-1 dialects) than it would be to port to other Lisp-2 dialects. But that certainly doesn't make Lisp-1 dialects "not Lisp" while Lisp-2 dialects are "Lisp".
Would you consider Scheme a lisp? It is after all also not sharing any code with the above mentioned (by necessity, since it use define instead of defun for declaring functions).
Other Lisp dialects, not implementations. Common Lisp has "implementations", Scheme has "implementations". The word "implementation" implies a high degree of compatibility.
In any discussion involving Common Lisp, there will be the opinion that "Clojure is not a Lisp" without (in my view) providing sufficient context for this clearly confusing statement.
(FWIW, I call Clojure a Lisp. It is clearly in the Lisp tradition, not to mention more technical things like: code-is-data, serious REPL, accurate numbers like 10.00000000000000001M. I don't think "Lisp" should be reserved for mainly incremental improvements on an old movement.)
That’s not a quote. You capitalized "Code-is-data" as if it were starting its own sentence. Had you quoted the whole sentence, your response would've seemed more like a non-sequitur.
In any case, there is no definition of even "chair". (Which partitions the world into chair and not-chair. Simply imagine a continuum between a particular chair morphing into a not-chair; where exactly does it stop being a chair?) So I'm unconcerned about edge-cases, where a language is actually in a fuzzy part of that continuum. Not to mention those amusing blogposts claiming "Javascript is a Lisp!" which maybe aren't objectively true but inspiring.
I keep seeing people make this statement, without any explanation of why. To me, hardly a heavy user of other Lisps, but with enough time spent in Common Lisp and Scheme to have an idea of what's going on, it feels pretty lispy.
I assume there's no official hard definition of what it means to be a Lisp. It's like "Pythonic". A warm fuzzy feeling that not everyone will share about the same things. It depends on what they consider important / good about a language.
Is C++ a C? Is Oberon a Pascal? Is F# a ML? Is C# a Java? Is Go a Squeak? Is Objective-C a Smalltalk? Is Javascript a Self?
No, not really: it's as controversial as Common Lisp's Lisp-n nature (which is to say, both of which are controversial amongst Scheme programmers writing Common Lisp). It's a perfectly useful macro. ITERATE is a bit more traditionally Lispy, and is an easy library away if one wants it.
> I don't think it's fair to say that its use is idiomatic.
Not using it is typically less clear. It's part of the standard; it's more elegant than using other parts of the standard; it's idiomatic.
Eh, no, it was controversial when it was being developed in the early '80s, a lot of respectable Lispers didn't like it, thought it was too complicated and easy to get wrong. But Common Lisp also has simpler constructs like dolist that aren't, to my knowledge, "controversial", except of course as you note this paradigm isn't a Scheme sort of thing.
It's idiomatic to use a sublanguage. Think FORMAT. CLOS. Control flows using the condition system. LOOP is just another style to extend Lisp. There are older libraries which use similar style.
Simple example from Winston&Horn's book LISP for a database query language:
Note that Common Lisp does not require tail-call elimination, so recursion is not really a standard operation. There's no one who thinks LOOP is a crawling horror than me, but it or something like it is your only option.
If one looks at music software in Common Lisp, the code is on a higher level than building lists like that.
> Secondly, this code tries to handle lists in the classic Lisp way, with recursion, and that's not what you typically do in Clojure.
Neither is it done in Common Lisp.
> Those 7 lines of Common Lisp compress to 2 lines of Clojure
The actual difference is that Common Lisp uses LOOP and not FOR, and that LOOP needs two nested LOOP forms:
Two iteration forms in a LOOP don't nest, but provide iteration bindings similar to LET* and LET: and Common Lisp's ITERATE macro also needs nested forms, but slightly improved over LOOP: The author of Clojure knows these differences very well, since he was a heavy Common Lisp user for a few years.> But, at the same time, if you're looking to translate stuff from other Lisps into Clojure, it's not going to be just copying and pasting. Beyond inconsequential, dialect-level differences like defn vs. defun, there are deeper differences which steepen the learning curve a little.
That's true. Clojure is not a Lisp, but partially derived from it, with many other influences from Haskell and other languages. It's mostly incompatible to Lisp: software can't be shared or copied, it needs to be complete rewritten. Thus basic Lisp literature is only of use when it's about features which got copied. For example the book 'On Lisp' might help to understand macros in Lisp and Clojure, whereas books like 'Practical Common Lisp' or Norvig's PAIP aren't very useful for Clojure programmers.