Hacker News new | past | comments | ask | show | jobs | submit login
The Evolution of Lisp (1993) [pdf] (umbc.edu)
155 points by swatson741 4 months ago | hide | past | favorite | 130 comments




That website's homepage really takes me back to the Old Web:

https://www.dreamsongs.com


Related:

The Evolution of Lisp (1993) [pdf] - https://news.ycombinator.com/item?id=14937424 - Aug 2017 (17 comments)

The Evolution of Lisp - https://news.ycombinator.com/item?id=3528694 - Jan 2012 (4 comments and a video re-enactment from 2008: https://www.infoq.com/presentations/Lisp-Guy-Steele-Richard-...)

The Evolution of Lisp [pdf] - https://news.ycombinator.com/item?id=2082417 - Jan 2011 (1 comment)


Please link to uncut version on Gabriel's own site.

See https://news.ycombinator.com/item?id=40484444


The abiding value of Lisp may be that it's a talking point, in the idea of what a programming language is.

Forth has a similar quality. The reductionist sweetspot of "implemented as a stack language" and "one step up from machine code"

C is the "no guide rails" conversation. Some would say it's one step down from assembly because it has none of the rigour and only some of the speed. That lack of rigour, the ability to cast within a memory region if you know how your structure maps into that region, I find extremely useful. Pascal's version of it was more clumsy but that said, perhaps the semicolon (and full stop) alone make Pascal part of the C family.

(you can't directly compute over a value in both float and int in assembler if you are in the ALU/FPU register space. You do "cheats" which are not rigorous, but more rigorous than C)


I discovered LISP late in life. For a long time, I didn't understand it at all, and reading that LISP was the most natural, the clearest and the most beautiful of all languages didn't help. Until I discovered that LISP was a dialect of lambda-calculus. For a long time, I didn't understand it at all, so hermetic was this formal language dating back to the 30s, and apparently reserved for an academic elite. But then I realized that it was nothing more than a sophisticated text replacement tool. So, using a single regular expression and a few lines of javascript code, I wrote an s-expression evaluation/reduction engine. Then I added 9 special forms -- lambda, def, if, let, quote, macro, style, script, require -- to end up with a real language, lambdatalk, capable of taking advantage of the web's tremendous potential. The result can be seen here: http://lambdaway.fr . I explored many algorithms, and even if this exploration remained solitary, I learned a lot. This is my LISP experience and I don't regret it. Thank you LISP.


Is there any old or new Lisp variant with excellent, beginner friendly (or even loving) documentation?


Racket might be the best bet, especially since it comes with a graphical IDE - Emacs is a big stumbling block for beginners. Racket also has lots of tools that make it fun and practical for learners (e.g. creating static websites, simple GUI applications). Things like this seems like the best way to learn without getting bored or frustrated: https://docs.racket-lang.org/quick/


It depends on the kind of beginner. GNU Emacs has a built-in tutorial to get started on using the editor. After that, there's an introduction to Emacs Lisp as part of the info documentation in most packaged versions of Emacs. Extending Emacs is as practical a way to learn Lisp as others.


https://janet.guide/ this document can definitely be described as loving.


Check out Conrad Barski's Land of Lisp: http://landoflisp.com/


I wouldn't recommend Land of Lisp for beginners. It assumes a lot of basic Lisp knowledge and diverges from a lot of convention. If you're just starting out on your Lisp journey I'd recommend Touretzky Common Lisp: A Gentle Introduction to Symbolic Computation, which the author has a PDF of online for free.

https://www.cs.cmu.edu/~dst/LispBook/


I worked through the first 9 chapters of the Touretzky book as a preparation for PAIP recently. It's very thorough. If you work through the exercises in the book, you'll learn a lot.


there's a reason why people on forums and chans consistently recommend land of lisp over other books, it's deliberately imperfect in a way which appeals to a certain kind of young hacker's mind. it doesn't assume basic lisp knowledge, it assumes you're going to type the program in without understanding and then figure it out from exploration. it also assumes that you won't understand the whole program immediately or even after reading the whole book. it's a different didactic approach, and is modeled after author's personal experience of learning how to program by typing BASIC programs from magazines. as such the programs are deliberately "misarchitected", they are somewhere between scripts and hacks that present a variety of ways in which common lisp the standard allows you to solve this or that problem. they are also designed to be "tasty", compact and quirky, as opposed to well structured, plodding and dogmatic. they are lifted directly from a wizard's laboratory and they invite play.

by comparison touretzky is a college level slog, solid, dependable coursework, that takes you over all the proper subject matter in a way that's certain to be approved by any computer science department committee, but that fails to create any sort of motivation to engage.


I second Emacs Lisp. Call `emacs -Q` (to open it without an init) and press enter. Emacs should have started with the default splash screen open and the cursor over the link to the tutorial. Read the tutorial and understand the basics of Emacs.

Next, read An Introduction to Programming in Emacs Lisp. It's a lovely book and fun to read: https://www.gnu.org/software/emacs/manual/html_node/eintr/in...

Learn to read and work with Lisp by reading the Emacs source code and playing with it.

Check out the Evolution of Emacs Lisp. It's a neat little Lisp! https://dl.acm.org/doi/10.1145/3386324

Emacs has the best documentation and documentation system ever made. Learn C-h f, C-h v, and friends, as well as the info system and the power of indexes.

I hope you find joy and wonder exploring Emacs and Emacs Lisp like so many others have for nearly 40 years!


Emacs Lisp is known for its great documentation, but I bet you're not asking about that. Try Fennel - it's a zero-overhead Lisp->Lua compiler. 'Zero-overhead' means that Fennel compiles directly to Lua without adding any extra runtime costs or abstractions beyond those present in standard Lua, ensuring Fennel code runs as efficiently as native Lua code. It has a relatively small set of features and is a very lovely language. I use it for dealing with things that need Lua - Hammerspoon, AwesomeWM, Neovim, etc. I jokingly call Fennel "the best Lua formatter" because Fennel code looks much more compact, cleaner, and easier to reason about than Lua. Lua syntax is weird, and I can never figure out how to format it for the best readability; standard tools and formatters rarely help here, sometimes making things even worse. The problem I almost never had with Fennel.


Can you share an example of Fennel with AwesomeWM?


There are plenty: https://github.com/search?ref=simplesearch&q=language%3A%22F...

Here's mine, https://github.com/agzam/awesomewm.d/blob/main/src/_init.fnl

Beware though, I'm not highly experienced in using and configuring Awesome (especially for beautification), the code is not meant to be shared and it has tons of dirty parts (result of my experimentation), I only built what I needed for my personal use.

Bigger (more public) project built on Fennel is https://github.com/agzam/spacehammer It's for Hammerspoon though, and my guess you're using Linux, not Mac.

One of the aspects I still haven't figured out is the "proper Fennel REPL", it makes certain things less joyful to write or troubleshoot, but even without it, I see some benefits in using Fennel instead of Lua - it's more compact, more FP-oriented, has macros, and it's a Lisp - I can use structural editing.



Plus the community spec, of course: https://cl-community-spec.github.io/pages/index.html


R6RS has a book that describes everything simply except for setting up the interpreter. [1]

Racket has all of that and everything else you need to get started like tooling and modules. [2]

Both lisps are no nonsense scheme variants.

[1](https://www.scheme.com/tspl4/) [2](https://racket-lang.org)


I was going to suggest Racket, too. Its documentation is some of the best I've ever come across. It doesn't hurt that it's beautiful, too. I smile every time I use Racket or its documentation.



Sicp for scheme


Got a link to fairly simple examples comparing Lisp solutions to those in another more 'mainstream' language (e.g., C, Python, BASIC, Java) that illustrate the benefits of using Lisp over another language for a 'practical' application? Thanks!


> simple examples comparing Lisp ... that illustrate the benefits of using Lisp over another language

It depends on what you're trying to get out of it. For example, you can grab a simple code of some React components with JSX and ask ChatGPT to write it in Hiccup (Clojure). That would show you how s-expressions can reduce the syntax boilerplate and make it smaller. You can do the same thing with Lua and Fennel - Fennel code would be much shorter and cleaner.

However, without proper understanding and using structural editing and connected REPL, you probably won't see any benefits right away. Lisp code is not the best to be read off the "dead medium" - paper or screen. It's better when you have a connected REPL because it allows you to evaluate every single expression on the fly. Instead of trying to understand what (foo x y z) means, you can evaluate it and immediately see the results. With a connected REPL, you can evaluate them separately (individually), or together. Good talk of relevance: "Stop Writing Dead Programs by Jack Rusher" https://www.youtube.com/watch?v=8Ab3ArE8W3s

Next step in understanding the benefits of Lisp code is learning structural editing. Because everything is a symbolic expression, you can easily move, transpose, change, and replace parts of your program. Instead of rewriting a function of seemingly arbitrary syntax constructs, you'll be dealing with well-structured forms that you can easily move around. No, it not the same, better or worse than using refactoring features of your IDE with other (non-lispy) languages. It's just different.

These two aspects - REPL and structural editing - are really difficult to explain; one has to experience them in person to see if that way of writing software feels appealing to them. And yet, without grokking the basics of these two essential things, IMO, the Lisp experience will not be the same, and you may not get why some people get really excited about Lisps.

And If you're truly looking for a brain-bender, check out https://github.com/hyperfiddle/electric. Dive into the concepts, play with the example demos, and see where it takes you. But be warned: it's an incredibly dense project and definitely not for the uninitiated. If you haven't written in Clojure before, chances are you won't fall in love with its ideas overnight. But it's a good example of "practical applications" that are difficult to achieve unless you're using a Lisp.


https://rosettacode.org

https://rosettacode.org/wiki/Category:Common_Lisp

This has a lot of problems solved in multiple languages.


Thanks, that is a great site! Will have to look at more, but looking at examples like the following, I'm not having a Lisp Aha! moment when I compare the Lisp and Julia/Python implementations, e.g.,

Cheryl's birthday https://rosettacode.org/wiki/Cheryl%27s_birthday

Seems like part of the problem is that Lisp is often demonstrated with examples that your average programmer can turn to 'black box' pre-built functions/packages/software for. That Lisp can help one extend a programming language to add a CASE statement, for example, is not going to win the hearts and minds of those who are already using a programming language with a built-in CASE statement. It may be neat from an intellectual standpoint, but not from a practical one.

And the merits of the example linked to below of how Lisp can be used to implement an in-memory database will surely be completely lost on anyone with access to in-memory database software like DuckDB.

Practical Common Lisp: An MP3 Database https://gigamonkeys.com/book/practical-an-mp3-database

DuckDB: SQL Introduction https://duckdb.org/docs/archive/0.8/sql/introduction.html


I don't think anyone should expect to get an "Aha! moment" from looking at algorithmic code. That's going to be the same in most languages.

If you want a "Lisp Aha! moment" you'd probably be better off looking at something that's actually Lisp-centric like Paradigms of AI Programming by Norvig (https://github.com/norvig/paip-lisp). You eventually build up to a Prolog to CL compiler written in CL.


Since there are other decent dynlangs out there, the benefits are less about the surface language aspect, and more about the process of getting to a solution. These are the system aspects of lisp that enable an incremental development workflow with a lightning-fast feedback loop. While there are important language features that support this, it's ultimately a "whole is more than the sum of its parts" effect.

I'd recommend checking out videos of people developing systems in lisp. Off the top of my head:

- https://www.youtube.com/@CBaggers/playlists

- https://www.youtube.com/playlist?list=PLTA6M4yZF0MzsMlNL0N67...


The Aha moment for Lisp can not be read.

You have to write code and experience it.

I mean, of course it has same cool constructs, but, at least for me, its the experience of writing code with it that makes it shine. And that kind of thing is intangible.

The iterative development experience is part of it. But, at least, the code I write has a rhythm to it, and I don't write other languages the way I write Lisp. Even at the 10,000 foot level, it's mot the same. For example, I tend to write more, smaller functions. Like Forth, its very easy to refactor Lisp. Being iterative and interactive, it supports and encourages that kind of thing.

Write a little thing, test it. Write another little thing, building on all the other little things, test those. (Note, not "write tests for them", just...test them. In the listener. "Good! Moving on!")

Find something that interests you, preferably something that's not "let's glue all of these other libraries together". Something that's going take 500-1000 lines. And, just write. Learn as you go, don't worry about being idiomatic.

See if anything pops from that.



Never seen Lisp-in-Lisp without additional (and boring) yapping. Just CAR, CDR and CONS. And assign and type-test and COND. It would probably be about 300 lines.

"Most beautiful program ever" is short but the associated yapping takes almost 2 hours. https://www.youtube.com/watch?v=OyfBQmvr2Hc


What's a good resource for learning to write a lisp compiler?


Look at all of them, then throw them away. Start with a lexer, a parser (pretty easy), the AST is already done, then it's all about the eval loop. All you need is sit down until you understand Lisp's metacircular evaluator (less than 50 lines or code), which is all you need to implement eval.

(I found this while writing this comment: https://bernsteinbear.com/blog/lisp/12_metacircular/)



Lisp System Implementation by Nils Holm is pretty good if you're a C programmer.



It is a very bad start and teaches writing an interpreter and not a compiler. https://gist.github.com/no-defun-allowed/7e3e238c959e27d4919...


Do you imagine it to be especially hard or impossible to replace an interpreter with a compiler instead of implementing a compiler from scratch? It makes it harder to have decided on the language design rather than inventing it in parallel?

From an interpreted Lisp system to a compiler it's mostly a slog of studying compilers and assembly (or machine code) and possibly translating the interpreter, which you can use to bootstrap the compiler implementation if you'd like.

It's common path, see https://mpov.timmorgan.org/i-built-a-lisp-compiler/ and https://bernsteinbear.com/blog/compiling-a-lisp-0/ .


It's especially hard when you don't have semantics for your language outside of what your interpreter does. Then the semantics of the language in the book are plain bad: there is only dynamic scoping (oh, and the book often has plain misinformation - the provided definition of "lexical scoping" is wrong), and setting a local variable only affects the innermost LET if you nest environments, since the interpreter deep-copies environments (as it does with everything, to cope with lack of GC).

The book also uses something more like fexprs than macros, which I don't have an opinion _outside of this book_ on with regards to language UX, but fexprs are generally harder to compile. That is in part because they control if/when their arguments are evaluated, but the fexpr-alike things here do not (instead "Q-expressions" delay evaluation like QUOTE). You still would want to do something about calls to EVAL though. The fexpr system _in this book_ also does have bad UX: it only incidentally works with dynamic binding (Shutt's lexically scoped fexprs explicitly pass the environment around) and it also leaks every variable binding from the fexpr function into what it evaluates.

The book also just doesn't cover compilers, so you're doing that slog on your own.


anyone got the .tex source for this?


People should clarify what they mean by "Lisp". It's not a programming language or even a family of languages, it's a whole different computing system which just happens to have a programming language syntax on top. To get the most out of it and benefit from the powerful CL REPL, one needs to use Emacs (also written in Lisp).

Some variants just drop that part and focus on the language only. Clojure and Racket are in that category. They lack the full power of CL; so they're just Lisp-syntax languages, not an actual Lisp.

Maybe this high barrier to entry is why Lisp hasn't caught on even after 30 years of CL standardization. People often don't want to learn a new IDE to get the most out of Lisp. And if they stick to their current IDEs, they only get a glimpse of Lisp through its syntax (and much limited macro system). At that point, it's questionable whether whatever remains of Lisp does indeed provide any advantage over more mainstream languages (e.g., instead of learning Clojure, why not just learn a functional language like Elixir or Haskell? It's not like Clojure gives you the full Lisp power anyway.)

Addendum: As one of the comments below mentioned (thank you @lispm), what I meant by "dropping the full power of Lisp" is the ability to modify a running program (continuation/restart system). Does Clojure REPL drop you in a new REPL in case of errors so you can literally change the running code or enter value for a missing variable?


Alas there are two schools -- those that consider Lisp to be a language with its cradle defined by JMC's "Recursive Functions of Symbolic Expressions and Their Computation by Machine" and descendants thereof (Lisp1.5, MACLISP, Lisp Machine Lisp, Common Lisp, Emacs Lisp, ...). Sort of like with C, where Objective-C is clearly a "C", similar with C++.

Then there is another school which considers the meta programability, REPL, syntax, ... the more philosophical notion of Lisp (Scheme, Clojure, Racket, Arc, ...). Some have no similarity with Lisp 1.5 descendants, and only share a superficial similarity.

Lisp seems to be the only language where people really want to argue that they are a Lisp, nobody tries to argue that Javascript, Java, PHP etc are "a C" (similar syntax? semantics?). Does it even matter what is "a Lisp"?

The barrier for Lisp (be it one school or the other) is about as high as Python, you type the name of the implementation and do stuff. CL specifically doesn't say anything interesting about the REPL (e.g., SBCL doesn't even allow by default to navigate forms on the command line), so to say that it is "powerful" is very misleading. Similar about the requirement of Emacs, you can use anything you like.


There is a third school: those who consider "Lisp" to refer to, in a historic context, a specific old language that is no longer in use (which was actually called LISP), and in a modern context to a fairly diverse family of languages.

People don't argue whether Javascript is "a C". However, people do argue whether GNU C is C. Some pedants insist that only ISO C is C and that, for instance, GNU extensions like nested functions are not C. (And are off topic in the usenet newsgroup comp.lang.c.)

To me, C++ is a dialect of C. In fact, you can write production code in a language that compiles as either C or C++ and behaves the same way, with similar executable size and performance. When you do that, there are obviously C++ features you cannot use, but also C features you cannot use.


>dialect

Not true from long ago. By far, that's statement it's pretty wrong. You will get zillions of bugs and compilation errors in both ways.


I mean, say, draft C23 and C++20 are still dialects. There is a large subset that is mutually intelligible and useful for production work.

C23 is closer to C++ in one small way: () is now a prototyped parameter list, meaning the same as (void). Thus if you want to program in a common C23/C++ dialect, you can drop the (void) kludge now.


> Lisp seems to be the only language where people really want to argue that they are a Lisp, nobody tries to argue that Javascript, Java, PHP etc are "a C" (similar syntax? semantics?). Does it even matter what is "a Lisp"?

Lisp is far from being the only family of languages. There's the APL family, with k, j, q. There are the many Forths, to the point where it's been quipped that the language has more implementations than users. The C family rather clearly includes C++, Objective C, and D, as well as C itself (Swift and Rust are arguable here).

I wouldn't put the three languages you named in the C family, but they're all Algols in a manner of speaking. At least, I routinely describe them that way, and people tend to understand what I mean. The reason no one argues that those languages are in the C family is just the broad and informal consensus that ABI compatibility is the most important feature, rather than syntax.

Any time there's taxonomy going on, you'll have lumpers and splitters. I'm a lumper where Lisps are concerned. I would call Dylan and Julia Lisps, and have done so.

If anything, what makes Lisp unique here is a faction of Common Lisp users who feel strongly that the only Lisp is Common, and historical variants which lead up to the Hyperspec (elisp being grandfathered in on that basis). I've never entirely understood this, but I don't let it bother me. That appears to be the source of the argument you reference in the section of your post I've quoted.


Does it matter what is a Lisp? We can answer it like this.

Yes, it matters in the following way. New languages being touted as Lisps, which deviate from the Lisp characteristics, cause confusion.

For instance, nowadays you read comments like: "I tried Lisp for a while but couldn't get used to doing everything using immutable sequences, nice as the pure functional paradigm might be conceptually". Obviously, that person is referring to Clojure, and since Clojure is promoted as a Lisp, they believe that all that is true of Clojure is true of Lisp.

People believe such misleading statements which is then harmful to the real Lisps. Someone out there will avoid using Common Lisp believing that they would be required to do everything using immutable sequences or hashes.


> Clojure (/ˈkloʊʒər/, like closure)] is a dynamic and functional dialect of the Lisp programming language on the Java platform.

https://en.wikipedia.org/wiki/Clojure

I believe I've said this to you before in the context of Scheme: the Common Lisp community doesn't get the final vote as to what is or is not a Lisp.

As to your example, it's at least as likely that someone would be turned off Lisp by using Common Lisp, and someone else might suggest Clojure as a remedy to whatever issues they had with it.


> someone would be turned off Lisp by using Common Lisp

But that's at least a consistent situation. That user experienced an example of actual Lisp and was turned off.

> suggest Clojure as a remedy

So, there it helps Clojure to just be Clojure and not to identify as Lisp, what the user was turned off of.


Clojure is a Lisp.


Of course it is. Does it have the following?

- Code as Data? Check

- Homoiconicity? Check

- First-class Functions? Check

- Macro System? Check

- Automated memory management? Check

- REPL-driven interactive development? Check

I don't know what else do they want. I feel like this is some kind of "programming language racism" and "Lisp eugenics" bullcrap.

Yes, Clojure is different than Common Lisp, but it is important to recognize that diversity in languages and their ecosystems can be valuable, and differences don't diminish the contributions or identity of a language within the broader Lisp family. Why can't we instead borrow good ideas from Clojure and implement them in CL and vice-versa?

I love Lisps. I love Common Lisp and Clojure, Fennel and even Emacs Lisp. Whenever I need to jump between Javascript and Typescript or even between different frameworks, I feel like I'm programming in different languages. That doesn't happen with Lisp. I can relatively easily switch between Clojure, Clojurescript, Clojure-Dart, Fennel, Emacs Lisp and CL and still feel like I'm programming using the same language. Completely different platforms - same language. I really don't understand what this fuzz is about. Clojure is a Lisp.


OK, you have rules for what is and is not Lisp. Rules different from yours are wrong. Gotcha!

I think that the lack of an interactive experience is not necessarily a deal breaker. We could have a Lisp implementation which compiles to an executable image which doesn't run until uploaded to a target. This could use an existing dialect like Common Lisp or Scheme and be used by Lisp programmers to deploy some of their existing programs.

If you were to fix your rules to be more inclusive, it would be more consistent with your diversity rhetoric. (Not saying you should do anything; your rules are your business.)


> OK, you have rules for what is and is not Lisp.

These are not "my rules," I didn't make up this shit. Many renowned computer scientists have spoken about Clojure and at Clojure conferences: Guy Steele, Paul Graham, Matthias Felleisen, Gerald Jay Sussman, Daniel Friedman,... [some names just off the top of my head]. I'm pretty sure, if not all of them, most of them would definitely say "Clojure is a Lisp". So, until someone of that caliber steps onto the stage and tells us differently, that's what I'm calling it.


People already say CL is functional, whether they've used Clojure or not. It's a common misconception. The problem is most people on Hackernews are talking about languages they've barely used.

Incidentally it's MORE confusing for people to say Clojure is not a LISP.


Just because there are other sources of misconceptions about Lisp doesn't justify Clojure being one. Clojure could help by emphasizing that it's a Lisp-like language, which is different from other Lisps. On the clojure.org home page, there is this paragraph:

Clojure is a dialect of Lisp, and shares with Lisp the code-as-data philosophy and a powerful macro system. Clojure is predominantly a functional programming language, and features a rich set of immutable, persistent data structures. [...]

It would be helpful if this said something like:

Clojure is a dialect of Lisp. Though sharing with other dialects the code-as-data philosophy and a powerful macro system, it is very different from the original LISP of John MacCarthy, and the subsequent mainstream languages like Common Lisp and Scheme that are in contemporary use. Unlike these, Clojure is predominantly a functional programming language, and features a rich set of immutable, persistent data structures. [...]


Helpful to who? A home page is for conveying essential information. This paragraph is something you wrote to satisfy something pedantic that most people don't agree with.

Obviously the author considers Clojure a lisp and I dare say Rich Hickey knows what he's talking about.

I brought up the functional point because it's ridiculous to say Clojure is confusing people into thinking all lisps are functional. There's no reason to think that


> This paragraph is something you wrote

Yes?

> something pedantic most people don't agree with

How so?

> Obviously the author considers Clojure a Lisp

The revised paragraph still insists that Clojure is a dialect of Lisp, like before.

> ridiculous to say Clojure is confusing people into thinking all lisps are functional

I've witnessed it first hand a number of times now, from people whose only exposure to the Lisp world is Clojure.


You're saying Clojure is a lisp here, but every other comment of yours says the opposite. That's what I'm responding to.

>> This paragraph is something you wrote

> Yes?

I don't know why you're chopping my sentences in half to have fake points to respond to. I was saying the paragraph was written by you and for you. It is not helpful for beginners trying to get into a language to read random names and other languages thrown at them, and be told "It's like this other language you don't know about, but not quite." That's how you get people clicking away from your site.

It's just a weird hill to die on to say there's a problem with calling Clojure a LISP because it will "confuse" people. It doesn't confuse people that know what LISP is. Beginners are always going to be confused, that's par for the course.


You took clause #1 .. family of language and ignored clause #2 .. where people argue about admissability into the family.

The point is not "only family" its "only family, where people argue about being in the family"

I think it's actually not the only language family where people argue about admission. But that doesn't seem to be your point.

Your point seems to be "there are other families"


My conclusion, rather, was that the Lisp family is the only family where people argue against languages belonging to that family. Your statement was that it's the only family where people argue for languages belonging to it.

Much of my reply was a response to the other clause I quoted, about no one arguing that JS, Java, and PHP, are "a C". I pointed out that the reason for that is simply that no one thinks of them that way, superficial syntax resemblances aside. There is in fact a C family, but it happens that you picked three languages where neither users of C family languages, nor users of the languages you mention, would argue that those three are a part of it.

You'll note that arguing for vs against is not a disagreement: if someone is arguing against inclusion, that rather implies that someone is is arguing for it. Rather, your last sentence posed a question, based on your observation. My reply, which explains why there's such an argument to begin with, was intended to answer it.


Why do you say that one needs to use Emacs? Like, I love using Emacs for the elisp and having the power of a full lisp machine, but for CL I didn't find sly-mode/slime to offer anything particular paradigm-shiftingly more powerful than the vim/nvim adaptions?

This very side is written in CL in vi, if I'm not mistaken?


It's written in arc, a lisp language Paul Graham created. I think you're right about vi, though.


The site is written in Arc, which is a language written in an older version of Racket.


> Clojure and Racket are in that category. They lack the full power of CL; so they're just Lisp-syntax languages, not an actual Lisp.

That's pretty debatable that Clojure and Racket lack the "full power of Common Lisp". For one, they're all three different languages, each one having something the other doesn't. And another is that Racket is not a Lisp and doesn't purport to be. It's very much in the Scheme camp, but even then it is clearly it's own thing.


You don't need to use Emacs to write Lisp, just like you don't need to use the ISPF dataset editor to write COBOL.

That said, unlike COBOL, most of whose programmers these days use Visual Studio Code or a modern IDE, Emacs is still the best readily available support one can get for Lisp programming -- and that's kind of a black mark against Lisp. I really wish Allegro or somebody would deliver a modern IDE for an affordable price, or at least good VSCode plugin support.


Some folks prefer the LispWorks IDE.


LispWorks is great but the Personal Edition isn't good for much beyond classroom exercises and even some of the hobbyist versions can run you four figs. Not exactly enticing for those looking to get started.


Oh, come on. Next, you're going to claim that Clojure is not "an actual Lisp" because it contains neither "Common" nor "Lisp" in the name? Clojure is a proper Lisp. Period. It's homoiconic, it has macros, it is a Lisp-1 Lisp, not "kind of a Lisp-1 thing" or "a thing with a Lispy syntax." It is a proper, legit, respectable addition to the family of Lisps. Yes, it's not a Common Lisp, but it's a Lisp nevertheless. A three-wheeled car is still considered a car. While it may fall into a specific category of vehicles and sometimes be classified as a motorcycle or under a special designation depending on the jurisdiction, it is generally recognized as a type of car.

> why not just learn a functional language like Elixir or Haskell

Have you ever considered that specifically because Clojure borrowed some ideas from Lisp, some from object-oriented languages, and some from FP, it makes it a really good choice for certain applications and developers?

Besides, is it really a big deal not to have proper continuation/restart in Clojure? It really depends. For many use cases, the error handling techniques in Clojure are adequate and align well with its functional paradigms. I've been using Clojure for several years and haven't heard anyone seriously complaining about the lack of continuations, despite many former Common Lispers now being full-time Clojuristas. There are also some philosophical differences: The philosophy behind Clojure focuses on simplicity and building software with different tools and techniques, which can achieve similar robustness in practice. So, I don't know. Sure, I personally wouldn't mind having built-in support for continuations in Clojure, and there were some attempts to bring that via libraries, but this was never a "high priority thing" for Clojurists. If in 17 years of existence of Clojure (and almost 40 years of Emacs Lisp), that never became a thing everyone wants, I guess it's not as critical as you paint it to be.


"continuations" are not in standard Common Lisp. They are a Scheme feature (-> functions which capture a state of computation). Common Lisp has a standardized exception handling system called the "Condition system", it features conditions (-> exception classes), handlers and restarts. It provides a non-terminating exception handling system, also often with a user interface -> the user can choose a restarts via some menu system or in the REPL. Something similar is in Smalltalk, which provides excellent tools for error handling and debugging.

Lisps prior to Common Lisp usually had elaborate ways to handle runtime errors and extensive REPL interfaces for it, for example the break loop -> a REPL in the error context. The most prominent and widely cited was the one of Interlisp, which featured also user facing automatic error repair (-> DWIM).

Whenever I see a Lisp, which doesn't stop at an error and then let me look at it, I feel sad.

GNU Emacs is an application (a text editor) -> debug-on-error is by default NIL. That makes sense in an application.

> that never became a thing everyone wants, I guess it's not as critical as you paint it to be.

People asked for it, it seems. But the answer was no.

See for example "https://vimeo.com/223309989", "REPL driven development". It was a topic in the Q&A at the end.

Also: Since JVM/Java already has a built-in exception handling, why build another one?

There are some libraries...


Ah... it's that thing that stars a debugger when you hit an exception, right?


Common Lisp has the Condition System [1] and that is not a continuation mechanism, though it may seem similar because you can stop a computation and resume it with a different value, for example. I think that to classify as a continuation, CL would just need to expose the condition system's internals to allow the user to choose how to "use" it, but as it is, you can't: the only way to use conditions is to have predefined handlers for them... I remember that this was an important difference because with delimited continuations you can implement stuff (like async/await I think - probably most Monads?) that you can't in CL's Condition Systems (I can't find the article talking about this right now, hopefully someone else can chip in).

[1] https://lisp-docs.github.io/cl-language-reference/chap-9/j-b...



Lisp is a family of languages. They share a common ancestry. That family is larger than Common Lisp, although Common Lisp is might be the last living descendant. While there are common traits among members of the family (parenthesized notation, certain special forms, symbol names), the presence of these traits does not itself define the family any more than having fins implies that an animal must be a member of the fish family.

A language is not only its syntax, but also it's semantics. Lisp is not just parentheses or even 'homoiconicity.' In addition to the surface syntax, there is a shared cultural understanding of what certain symbols mean, how they fit together into a system, what a symbol even is, and so on.

Given that, while there is some surface resemblance to lisp, it's plainly obvious to me that Clojure does not belong in that family. This is not a dig at Clojure! Clojure makes a lot of people happy and productive, and that's great. It's my third favorite language on the JVM. But when you take a closer look at some very core design decisions made in Clojure you'll find that they depart strongly enough from all the other languages in the Lisp family that it belongs to a distinct language family. A few of them:

- Reader doesn't intern symbols

- EQUAL symbols aren't EQ

- Introduction of vars

- Cons doesn't cons

- No numeric tower

- Backquote behavior

These things don't necessarily come up in day-to-day programming, so it might seem like quibbling, but these are fairly central differences in meaning.

I think it's sensible to consider "Clojures" as a distinct language family. Rhere are languages like Fennel and Hy that are clearly Clojures, and I'm sure there will be more.


What would be the point of equal symbols being EQ in a functional language? They are effectively EQ because it can compare by value quickly.

Also, is there anything good about cons? It seems like the most obtuse way to do a sequence unless you need something funky that you could implement yourself.


Yeah, "consing" isn't such a big deal in Clojure because its philosophy revolves around "sequence abstraction," which is a significant improvement over the traditional approach. Lispers with a limited understanding of Clojure often criticize its departures from Common Lisp, such as using square brackets for function arguments, without grasping the reasons behind these choices. Once you understand Clojure's destructuring, you'll immediately appreciate the utility. Yet some people resist even hearing about contemporary techniques like modern irrigation methods and cloud seeding, and they'd rather stick with ancestral rain dance rituals simply because that worked for thousands of years.


I'm not here to debate taxonomy. Rich Hickey says: "Clojure is a dialect of Lisp and shares with Lisp the code-as-data philosophy and a powerful macro system." No disrespect, but unless Alan Kay or Guy Steele come to your side and convince Rich to stop calling Clojure a Lisp, I'll be calling it that. Sorry, maybe Mr. Hickey knows better than I do about the language he created?


"Being a Lisp" or "being a dialect of Lisp", these are two different things for me.

But even the "dialect of Lisp" actually is more like "spiritual dialect of Lisp".

Clojure was from the beginning designed with exactly ZERO backwards compatibility to Lisp. Exactly ZERO of the existing Lisp programs/libraries could work. It was even difficult to port them. It's basically a kind of "dialect" with new operators and data structures, which interprets prior concepts in new ways and mixes in new stuff.

But it was designed with compatibility to Java and the JVM -> one could not reuse existing Lisp code, but one could reuse existing Java code -> since Clojure was hosted on the Java and had integrated calling Java code. Reusing Java was more important, because the goal was to work in a Java industry. Thus there wasn't a version of Clojure on top of Lisp, only versions on top of languages/infrastructures like JavaScript or .net, because there was another source of reuse.

If we look at the above linked paper "The Evolution of Lisp", then "Evolution" actually meant "Evolution", not "Restart" -> the language evolved by improving, adding, extending, removing, ... around a core design.

Clojure was designed as a new dialect, free of the baggage from the past, with a completely fresh start. Reusing existing code or evolving an existing language was a non-goal. It was newly designed as a hosted implementation (-> the Lisp runtime was gone), it was designed with lazy data structures at its core (-> the Lisp linked lists were gone), it was an opinioned new design, based upon of what Rich Hickey liked about Lisp and what would help him to be employed as a consultant in a Java world -> by developing upon and within the Java stack of standards, tools and libraries.

And that's fine for him. Rich Hickey had his goals and succeeded with them. Other people found it useful, too.


Okay, look. My native tongue is Russian. In Russian, "being a Russian" has two forms: "Русский" and "Российский." "Ethnic Russian" and "a Resident of Russia." When translated to English, the difference gets blended, but in Russian, it still exists. We can imagine some completely imaginary English dialects in which "Lisp" would have a different meaning, can't we? We can even add some weird rules similar to "Российский Флаг" and "Русский Флаг," which would be translated depending on the context and time differently. We would have to find ways to describe "the subtle differences of 'Lisp' in different contexts." We can pretend we're talking in different dialects where "Lisp" means different things. We can create all sorts of rules and standards. But at the end of the day, for most people, Lisp is like "porn" in the sense that "if it is, you know it." I'm in that school. Clojure is a Lisp to me. Call me a religious idiot. If people can't tell the difference between Common Lisp, Lisp, and Clojure, call them idiots. I don't know, usually when I mean to say "Common Lisp" I'd say it, or I would use "CL" and people usually know what I meant. Then I don't know what we're arguing about.


I usually don't want to call people "idiots", but I would want to prevent confusion. Even though English is a Germanic language, it's not German. It's a matter of expectation. If a book title says "Lerne Deutsch" it's not meant to mean "Learn English". Same for "Learn Lisp" and "Learn Clojure". Both books usually will be about different languages. For example there was a book "The Little Lisper", for Scheme it was renamed the "The Little Schemer". People then knew that the book is using the Scheme dialect of Lisp and not Lisp itself.

Btw., even though "lernen" and "learn" are coming from a common language background (Proto German, also called Common Germanic, no joke -> https://en.wikipedia.org/wiki/Proto-Germanic_language) and here mean the same.


> I would want to prevent confusion

There's no confusion. Anyone who wants to learn Lisp can start with Emacs Lisp, Racket, Guile, Janet, Fennel, Clojure, or Common Lisp, and soon they'd know how they differ. Telling people "Oh no, Clojure is not an actual Lisp" is disingenuous. Yes, there are certain differences, but the main ingredients are there - homoiconicity, macros, REPL-driven. Sure, in some contexts, clarification is required, and usually, it is present. I have never heard anyone say something like "I actually wanted to learn Lisp, but I ended up using Clojure and never found out what 'the real Lisp' is like." When people want to specifically talk about Common Lisp, they say that. Again, I have no idea what the fuzz is about, Clojure is a Lisp. Yes, it's not Common Lisp, it's not Emacs Lisp, we know that. Most people who know just a bit about Lisps, do know that. And yet we're arguing like someone accidentally may end up using wrong Lisp and kill thousands of polar bears or something.


-> the Lisp linked lists were gone

Cons cells and linked lists are not completely gone, though:

    user=> (cons 1 (cons 2 nil))
    (1 2)
Cons cells however are somewhat limited in that the second argument to cons must be an ISeq.


and then you get this in Clojure:

  user=> (list? (cons 1 '(2 3)))
  false
  user=> (cons 1 '(2 3))
  (1 2 3)
That's "strange", isn't it? It prints as (1 2 3), but it is not a list? So there are things which print as lists, but aren't lists? What? Which also means that when we print it and read it back, it will be of a different type and list? will be true?!

  ELISP> (listp (cons 1 '(2 3)))
  t
Puh, Emacs Lisp got it right.


I just tried your first example on tryclojure.org and it returned "true":

    user=> (list? (cons 1 '(2 3)))
    true


Your example looks like Clojurescript? It is also inconsistent between variants?

  Clojure 1.11.3
  user=> (list? (cons 1 '(2 3)))
  false


Interesting! The tryclojure.org website says it's Clojure, not ClojureScript.

If it's inconsistent between variants then I'm absolutely not going to code in it...


It's not "inconsistent" between the variants. Clojure is a hosted language, it depends on the underlying platform.

In Clojurescript, the implementation details and type checks differ slightly from Clojure due to the different runtime environments (Javascript vs. JVM). As a result, certain predicates like `list?` might behave differently.

In Clojure, it's generally better to use (seq?) instead of (list?) when you need to check if a value is a sequence, as (seq?) is more encompassing and works for all sequence types, not just lists.

You almost never use (list?) in Clojure unless you explicitly need to check for a list created via (list ...), and most of the time we use (seq?) instead.

Maybe Clojure doesn't work for you because you haven't even bothered checking the documentation? At least you could've asked Google or ChatGPT, before crying how "broken it is". The language after all wasn't created last weekend, it's been around for 17 years


Yes, I'm tired of Clojure fanboys recommending their language as a Lisp. It's not.


You can probably make many like minded friends in r/haskell. Just post something about Clojure and pedants most likely crawl out, saying how it is not an FP-language. :)


Not about FP; it' just that Clojure tries to be a Lisp and it fails on the simplest basic list cons'ing.

Like declaring some mini-C 'ANSI C compatible' and you can't even provide a complete but basic stdio.h header.


It's not "failing" on the simplest basic list cons'ing, it did what's expected, it consed the list. You're trying language features without even bothering to ask if the function you're using does what you think it does.

Have you read the docstring for (list?)? It says "Returns true if x implements IPersistentList". (cons 1 '(2 3)) results in a clojure.lang.Cons not the instance of clojure.lang.PersistentList. A clojure dev would be using (seq? (cons 1 '(2 3))) instead of what you tried.

Maybe before hating something so fervently try to learn it a bit more first?


> A clojure dev would be using (seq? (cons 1 '(2 3))) instead of what [the Lisp dev] tried.

Well, no kidding.

> (cons 1 '(2 3)) results in a <Java thing> not the instance of <another Java thing>.

:)


Clojure is a hosted language. It embraces the idioms, strengths, and ecosystems of the platforms it runs on (JVM, Javascript, .NET, Dart, etc.) without trying to "change the platform" or impose an absolute uniform behavior across different environments.

Clojure encourages using idiomatic patterns that align with the host platform’s best practices. For instance, when running on the JVM, it leverages JVM's threading model and garbage collection; in Clojurescript, it adopts patterns suitable for JS's event-driven model.

Clojure does not try to provide a uniform abstraction layer that masks platform differences. Instead, it exposes platform-specific capabilities, making developers aware of and able to exploit the unique features and strengths of each platform.

Clojure compiles down to the native code of the host platform. For the JVM, it compiles to JVM bytecode; for JS, it compiles to JS code. This means the compiled code runs as if it were natively written in the host language.

Clojure operates within the host runtime, using the host platform’s execution model, memory management, and runtime services.

Being a hosted language means that Clojure does not attempt to hide or abstract away the platform it runs on. Instead, it integrates deeply with the host platform, leveraging its native capabilities and interoperation features. This allows Clojure code to be idiomatic to the host environment and benefit fully from its strengths.


I can only add to that - the hosted nature of Clojure is one of the most underrated awesome features of it. You can write for example a macro that's defined in Clojure code, but to be used in Clojurescript, and changes the behavior of a browser app based on a condition detected in JVM - for example, you can parse some .js library and based on that (clojurescript compiler would) emit modified compiled Javascript code. That stuff is useful for dynamic polyfilling, i18n, css-in-js, feature-flagging, using shims to ensure compatibility, and more.

Moreover, you can have namespaces where Clojure and Clojurescript code is intertwined. I have never seen so much code reusability, even when I was heavily writing for Node. Check this out: you can write specs that would represent your data, alright? Then, you can generate some random collections of data based on those specs. The data that you can use both - on front-end (e.g., for end-to-end testing) and back-end (e.g., for testing the domain logic). You can also use the same specs for validation in UI controls - 'not a valid email', etc. Neat, right?


But why is a list not a list across all platforms?

Other Lisp dialects run on top of the JVM, .net, JavaScript, LLVM, UNIX, iOS, Android, Linux, ... and there is no such problem.

Try ABCL on the JVM. (listp (cons 1 '(2 3))) is T.

I would think that consistency and correctness of basic Lisp operations (-> LISP stands for "List Processor") would be a high priority of any self-respecting Lisp dialect?


Alright, your concern about consistency in basic operations is valid. Yet, it's important to consider the different design philosophies and practical constraints of Clojure and Clojurescript - platform-specific optimizations, type systems, practical trade-offs, etc.

To be honest, I never knew about this (list?) thing behaving differently with (cons) because I personally have never stumbled upon that. Most likely, people raised this question because, like I said, the language has been around for decades. I don't know the proper and accurate answer for you here, that's probably some intentional design choice rather than a bug, driven by the need to balance consistency with platform-specific optimizations and constraints; if that was important, I would've found it and known how to explain it. It is not important (think of it as an easter egg), because...

Like I said before, Clojure emphasizes using seq abstraction instead of lists. It is a core part of Clojure's design and works uniformly across Clojure, Clojurescript, Clojure-Dart and other variants. It abstracts over different collection types, allowing you to work with sequences without worrying about the underlying concrete types. Functions that return `seq` often produce lazy sequences, which can be more memory-efficient and allow for incremental processing. This is particularly useful for handling large datasets or infinite sequences. `seq` functions, such as `first`, `rest`, `next`, and higher-order functions like `map`, `filter`, and `reduce`, provide a consistent API and behavior across different implementations of Clojure. This minimizes the impact of platform-specific differences. In addition, it can often lead to performance optimizations tailored to the specific platform, as it allows the runtime to use the most efficient way to traverse collections.

Yes, Lisp traditionally stands for "LISt Processing," and lists are indeed central to Lisp's heritage. However, modern Lisp dialects have evolved to handle a broader range of data structures efficiently while maintaining the core principles of Lisp. Common Lisp, while having first-class support for lists, also has a broader set of data structures including vectors, strings, and bytevectors. Racket enhances the language with a diverse range of data structures—vectors, hash maps, sets, and streams. Elisp, too, has hash tables and strings. Clojure adds vectors, maps, and sets as first-class citizens. I guess that's why we no longer use "Lisp" as an acronym - we no longer capitalize each letter. I guess one could say "it is still 'LISt Processing' because every expression written in it is a list..." ¯\_(ツ)_/¯


LISP does not stand for "List processing", it stands for "List Processor". To quote John McCarthy: "A programming system called LISP (for LISt Processor) has been developed for the IBM 704...".

This is a programming system, which is a list processor. Not a vector processor, not a graphics processor, not a number cruncher -> it's a list processor.

Now McCarthy defines three basic LISP features:

* Data has the form of S-expressions, for which a definition is given, which is linked lists of atoms&lists. -> a very low level definition.

* There is a LISP language which processes these s-expressions. Simple operators are being defined.

* LISP can interpret and execute LISP programs in the form of s-Expressions.

To sum up: there are linked lists, a programming language for processing them AND the programs themselves can be interpreted by LISP.

He then defines an "universal LISP function", an interpreter for LISP in LISP.

That's the actual core essence of LISP. Think about it!

That's the big thing which was defined in the very first pages of the first LISP papers: a very simple foundation, which describes how to do computation by a List Processor, applied to itself.

This is the core language: a data structure, a few operations and an interpreter written in itself.

Fire up your Emacs Lisp (start GNU Emacs and do m-x ielm). It's all there: the data structure (-> linked lists of symbols), the operations (car, cdr, cons, read, print, cond, lambda, eq, assoc, append, ...) and the interpreter (-> eval).

It's not one of many data structures, it is the central thing: s-expressions, programs as s-expressions, a list processor (-> EVAL) defined in the language it is executing, executing programs which are given as s-expressions, able to execute itself.

All the other stuff you've mentioned is secondary: Homoiconicity, First-class Functions, Macro System, automated memory management, REPL-driven, interactive development.

McCarthy described a specific way to do computation. That's the core of LISP. One which can be taught in a day, which fits on a few pages and which allows us to develop a simple mental model of it.

Clojure does not have the same axiomatic definition of a List Processor, it is not interpreting lists, ... It has a complex data structure at its core: lazy persistent sequences, it compiles code (the compiler is written in Java and compiles to the Java Virtual Machine), it has the JVM underneath, ...

If I break the execution of a list processor, I see the programs as lists being executed by a lisp processor. Write a program in Emacs Lisp, execute it by the interpreted EVAL, run it, interrupt it and you'll see a backtrace where the interpreter runs the Lisp expressions.

If I want to teach people Lisp, I explain this simple LISP PROCESSOR. That's the mental model they need to have: the form of Lisp programs and its execution. Once they have this mental model of LISP, it is valid for all core LISP dialects.

This is also explained in the LISP literature: "LISP 1.5 manual", "Anatomy of LISP" (John Allen -> the book is available here for download: https://dl.acm.org/doi/10.5555/542865 ), "Structure and Interpretation of Computer Programs" (Abelson/Sussman), "Paradigms of AI Programming" (Norvig), "Lisp In Small Pieces" (Queinnec), "The roots of LISP" (Graham) and others. All these explain this foundation (and expand on it).

Clojure is slightly different. It's a modern&pragmatic&opinionated dialect of Lisp for the JVM, which does not have this simple LIST PROCESSOR. That's why it is an dialect of LISP, but not one which shares the axiomatic core of LISP.


While Clojure emphasizes lazy persistent sequences, it still uses lists as a primary data structure and supports list processing. The new data structures are extensions, not replacements, designed to address specific application needs more effectively.

Many classical Lisp implementations also compile code. Compilation does not preclude a language from being a Lisp. Clojure continues the use of s-expressions for code and data representation. Clojure provides a REPL, a staple of Lisp environments.

Clojure retains the homoiconic nature of Lisp. Macros in Clojure very much akin to those in traditional Lisps.

Clojure’s design choices are about extending Lisp principles to solve modern software engineering challenges. Rich Hickey wasn't like: "Lispers were all wrong..." He chose to build the language on top of Lisp principles, and these principles are evident, unmistakably clear and can be seen with a naked eye.

I'm honestly getting worn out by this debate. You're delving into the minutiae of taxonomy, like whether early hominids can be classified as humans, and it's just exhausting. I've told you before, and I'll tell you again — unless someone truly eminent persuades Rich and he eventually concedes, saying: "Yes, Clojure in reality ain't no Lisp..." only then will I alter my position. Until that time, I will continue to call it a Lisp, regard it as a Lisp, and talk about it as a Lisp. The only thing you can do to change my opinion - is to persuade Rich to change his.


You are on the surface. I'm talking about a computing paradigm defined by LISP. A foundational model at the core of the language, enabling us to understand how the List Processor actually works.

LISP has dialects which are not homoiconic, where programs are not written as s-expressions, ... But the core is the same: a specific List Processor. McCarthy himself did not want to write programs as s-expressions. He defined M-Expressions, where S-Expressions were only used for the data.

Check the book "Anatomy of LISP", which is a classic. All the code in the book is written in M-Expressions. Now, Racket gets a new syntax (-> Rhombus). But the language core mechanisms are still there. I'm a fan of the s-expression syntax, but I've also heard&read from many people (incl. McCarthy), that THEY preferred a different syntax. I've seen Apple defining Dylan (Dynamic Language) with an s-expression syntax and then changing the language to a different syntax for broader adoption. You (and me) think it is essential. McCarthy and others thought that it was the wrong syntax for getting wider adoption.

Btw., personally, I don't care that much what Rich Hickey says. I can think for myself.


It is fallacious to suggest that in order to have generic iteration that supports non-list objects, we must abandon the classic list processing functions and give them alternative names and behaviors.

In the TXR Lisp dialect, classic functions like mapcar iterate over nonlists, without losing a shred of backward compatibility over lists.

For instance, we can iterate starting from an integer, in parallel with iterating over a list:

  1> (mapcar 'cons '(a b c) 0)
  ((a . 0) (b . 1) (c . 2))
What we do is pattern the iteration abstraction after the car/cdr model, so that car/cdr iteration falls out as a straightforward special case.

To do this we define an iteration API with four operations:

  iter-begin: construct the iterator from the sequence object
  iter-more: test the iterator whether it has more elements
  iter-item: if iter-more tested true, get the first item
  iter-step: calculate iterator of rest of sequence
iter-step may be functional or destructive, so the caller must capture the new iterator returned as a value and must stop using the old one.

Integer:

  1> (iter-begin 0)   ;; identity
  0
  2> (iter-more 0)    ;; true function: ignores argument, returns t.
  t
  3> (iter-item 0)    ;; identity
  0
  4> (iter-step 0)    ;; successor function
  1
String:

  5> (iter-begin "abc")   ;; opaque iterator returned
  #<seq-iter: a0bef50>
  6> (iter-more *5)
  t
  7> (iter-item *5)
  #\a
  8> (iter-step *5)       ;; destructively stepped
  #<seq-iter: a0bef50>
  9> (iter-item *8)       ;; let's refer to *8 anyway
  #\b
List:

  10> (iter-begin '(1 2 3))   ;; identity, like in integer case
  (1 2 3)
  11> (iter-more '(1 2 3))    ;; not-equal-to-nil test
  t
  12> (iter-item '(1 2 3))    ;; car
  1
  13> (iter-step '(1 2 3))    ;; cdr with check
  (2 3)
  14> (iter-step '(1 . 2))    ;; demo of check
  ** iter-step: 2 is not a cons
Without the check in (iter-step '(1 . 2)) we would get 2, and that would then iterate through 2, 3, 4, ...


> Rich Hickey wasn't like: "Lispers were all wrong..."

Actually, yes he was.


Citation?


Clojure also has a powerful REPL allowing you to interact with running processes in Emacs and in other editors and IDEa


Clojure isn’t an “actual” Lisp because it’s not Common Lisp? Are you serious? Purity spiral much?


Parent stated that some variations drop the 'whole different computing system' part of Lisp; which makes them Lisp-syntax languages rather than actual Lisps. I believe he means things like modifying a class and updating all existing instances without having to restart the application, the continuation/restart system, and so on.

As an aside, please remember the guidelines: 'Please respond to the strongest plausible interpretation of what someone says, not a weaker one that's easier to criticize. Assume good faith.'


The comment was well within the guidelines and is a viable point. When people make broad statements on Lisp like the original great-grandparent comment, they really need to clarify whether they're talking about Common Lisp or Lisp-likes. The original LISP doesn't have the features that Common Lisp has, so it'd be weird indeed to say that LISP wasn't an actual Lisp.

In retrospect, the comment was talking about Common Lisp and not just Lisp-likes and tried to make the distinction but did a poor job of it with comments like:

> Clojure and Racket are in that category. They lack the full power of CL; so they're just Lisp-syntax languages, not an actual Lisp.


Common Lisp and/or its implementations (and a bunch of other dialects) have most most of the features of the original LISP directly, often with minor changes, like many of its operators and data structures (like the linked list). It was designed to be largely backwards compatible with earlier LISP. Original LISP implementation features like the self hosting machine code compiler, loading of natively compiled code and the ability to save/restore images of the Lisp heap (which really was already in the 1960s LISP) are also provided by various later Lisp implementations, incl. several CL implementations.


Paul Graham felt all development should be in Lisp. Problem is readability by maintainers in the future. To facilitate that, the number of characters in the comments would have to exceed that in the code.


> Problem is readability by maintainers in the future

Sounds like a problem that exists in every single programming language to date. And the reason that problem appears is not because of the languages themselves.


Some languages are designed with a strong focus in simplicity and great compiler errors to overcome that issue as much as possible. Gleam and Elm are some of them.


> Problem is readability by maintainers in the future.

Of course. That's why some massive projects got abandoned because nobody understood the code they were originally written in. Does anyone even remember Emacs, or AutoCAD, or Datomic? There were companies that went bankrupt because their Lisp codebases became obsolete. Remember Cisco? Or Apple (those idiots tried to build their payment system in Clojure), or Walmart? Or NASA (before they succumbed to the will of evil Elon). Maybe smaller companies like Pitch, or Funding Circle, or CircleCI, or Grammarly? No? Sigh, nobody cares anymore about the history of dead programming languages.


Do you have anything suggesting these weren't just abandoned like most projects are? Is there some interview with the CTO saying "Lisp made this impossible"?

We abandoned a project in Python. Is Python unusable?


I have weird sense of sarcasm, sorry.


No that makes more sense now lol.


Even with all those comments, it still ends up being less characters than other languages :D


Lisp is far and away the best of the nonreadable programming languages.


It takes getting used to it, just like every other programming language syntax.

If you are comparing it to the ones you are used to, of course you'll find it harder.

(IMO, I don't like the Lisp syntax, but it's really not "non-readable".)


It is hard to read though. As a beginner or someone unfamiliar with a new codebase you never know whether you are recursing into a special form or not. If you are, the semantics and order in which you ought to read and understand and further recurse into the argument list changes completely.

How other programming languages limit the depth of this recursion and the variation/complexity of a code block, by splitting the semantics into a limited set of reusable syntactic constructs is very powerful. It is sad that most aren't homoiconic though.


> It is hard to read though.

What isn't? Java or C# with deep hierarchies of nested classes and tons of boilerplate, extensive use of interfaces or overuse of exception checking?

Python with its magic methods and decorators and misindentation?

Javascript with the callback hell, inconsistent type coersion and sometimes tricky async code?

Ruby with its weird metaprogramming and monkey patching?

C with the pointers mental acrobatics and pre-processor macros?

Perl with weird default vars like $_ and tons of regexps?

Haskell with its monadic structures and heavy use of weird symbols and operators?

PHP with the crapload of its historical baggage, global vars and inconsistent, non-standardized function naming?

Any programming language can be considered hard to read, quirky, slow, inconsistent, or lacking some feature. Everyone knows there are only three God-given, bullet-proof, guaranteed ways to write robust, fast, consistent, bug-free and scalable software. Three... Humankind has yet to discover those.


It's all the way up at the best readable ones instead :)


Pfff... The Lisp syntax is one of the simplest, comprehensible, readable, no-BS sugar things. People with shallow experience often say it looks weird, but with some hands-on experience, you soon appreciate its elegance and power. The consistent, minimalist syntax becomes second nature and reveals its true beauty and functionality.

You can easily read Lisp code off your phone screen - it wraps around, but retains the structure. Try that trick with pretty much any non-lispy language - even "the most elegant Python" fails there, face flat.

EDN & Transit is far better than JSON - EDN is more flexible and expressive than JSON, making it a superior choice for data serialization. It's also more than two times smaller and cleaner, commas are completely optional.

Hiccup is better than JSX & HTML - far more easier, cleaner, shorter and nicer to work with.

similarly,

s-expressions are better that XML & Yaml;

CL's PLISTs and ALISTs & Clojure maps are better than Dicts/Hashes in other languages.

Basically, you can leverage the expressiveness and simplicity of Lisp-like syntax to offer structured, readable, and powerful data representations. Add to that the ability to evaluate any given form on the fly through a connected REPL, basically "trying things while you read them," and that changes everything you thought you knew about the readability of code.

Those who call Lisp "non-readable" I suppose, in fact, never tried to actually read it. Of course, if you never learn a language, it would remain incomprehensible.


Is there a spec for S-expressions as a data transfer format? I’d love to try it as an alternative to JSON.


There's SXML, which is equivalent to XML but in S-expression form. Seems to have only caught on in the Scheme community, though.

There are a couple standard ways to do dictionaries (a-lists and p-lists). Object systems like CLOS and GOOPS have standard text representations, but they're tied to their respective Lisps.


There isn't a single, universally accepted specification for s-expressions specifically as a data transfer format.

But like I said: there's EDN - primarily used for configuration files, data serialization/deserialization between systems, inter-process communication

And there's Transit - Ideal for scenarios requiring fast data transport over networks, such as web services and APIs, it supports both JSON and MessagePack encodings.


Yes, it's called XML.:-)


"Pfff..."? You're getting a little too defensive over someone not liking your language. You're just asserting that the language is easy to read and saying that anyone who disagrees just hasn't read it. This is some sad fanboy behavior that I don't like to see.


I've got your attention though, haven't I? :)

Defensive? No. I don't think Lisp needs defending.

Lisp is an idea. Good ideas need no defending. The invention of Lisp is one of the greatest events in the recent history of symbolic communication. It can be put in the same category as cave drawings, cuneiform, Egyptian hieroglyphs, and mathematical notation in the sense that they all represent systems of symbolic communication.

My "Pfff..." really comes from not understanding why people would say things like "Lisp is hard to read" when, in truth, it's probably the best tool we humans have for its designated purpose. Lisp emphasizes simplicity and uniformity, which can enhance readability and ease of understanding programs. With a big caveat, though, Lisp's readability improves with practice and familiarity. Many people find Lisp structures to be clear and expressive for symbolic manipulation and functional programming tasks. Okay, I mean I get it. Let's say I can, for example, look inside "Principia Mathematica" and completely find it unreadable. Yeah, I would. But wouldn't it be weird of me to go to a forum for mathematics and tell them that their math is unreadable? They'd probably decide that I'm trolling.


You got my attention that one time, sure. That's all you get.


Awwww. I thought we were becoming friends. I used a smiley face and shit... :[




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: