LispLanguage
ThoughtStorms Wiki
- PaulGraham (a big Lisp advocate) on it's history and what made it different : http://paulgraham.com/icad.html
I'm now getting into ClojureLanguage and RacketLanguage
- Lisp in Lisp : http://www.cs.aau.dk/~normark/prog3-03/html/notes/languages_themes-list-in-lisp.html
- LispAsATrainSet
- Lisp in JavaScript : http://ganley.org/software/jslisp.html
- NewLisp is Lisp for CGI scripting etc.
- TheCostOfSyntax
Must watch this : http://swiss.csail.mit.edu/classes/6.001/abelson-sussman-lectures/
What is "code-is-data"?
Most programming languages are stored as text. To operate on code, then, means you'll need to parse that text. Because characters don't correspond to the meanings. (Just like I'm not thinking in terms of letters right now; rather about words, sentences, etc.)
If you want to operate on code, it is best stored in a more convenient data structure.
That is a large point of Lisp, that code is stored in useful data structures. When Lisp was invented, OOP wasn't known. So one data structure used is the list. (Arrays, OOP objects, etc. could have been used, but lists were.) There are other data structures; for example, symbols, numbers, strings, characters, etc.
So this is a program:
42
And so is this:
(dog 42 "This is a text string!")
The program 42 merely results in 42. The last one is a list holding three things: the symbol dog, the number 42, and the string "This is a text string!". If it were executed as code, it would treat dog as an operator, to operate on the other two.
So Lisp is not about lists. It just happened to be one of the datastructures used in storing code, nothing more. But one that people notice, because those parens stick out.
What is the link to functional programming?
Lisp is not just about functional programming. It simply was perhaps the first programming tool which supported strong, useful functions. At some point, people built a religion around functions.
In fact, the old meaning of "recursion" was simply one function calling another. Nothing more. Today it means a function calling itself at some point.
In Lisp, you can store functions in variables, and there are a couple more useful features. But things which are part of a good meal may become unhealthy, if you eat it exclusively all the time.
In particular, those who teach Scheme frequently push functional programming. Of course, it is good to research it in a sophisticated way, but the temptation to hype it dishonestly is strong – just like OOP.
At the 2004 ECOOP conference, a quick poll showed that Lisp attendees used loop the most – loop is like every for(;;) loop in every language rolled up into one. So functional programming isn't that dominant. But you still see it often, even mixed in with other paradigms like iteration.
This is interesting. If I read you correctly you're saying that the "program is data" aspect of Lisp is more important and fundamental than FunctionalProgramming purism? And that many Lisp hackers are happy to use imperative styles. (I was reading my book on EmacsLisp last night and I was quite surprised to discover the "while" and "progn" operators :-) And at the same time, the lists aren't very important at all. Could have been any suitable data-structure which could also hold code. Although it's hard to think of anything else quite so flexible and suitable for holding code.
Lisp is a multiparadigm tool. So, the specific situation facing you pretty much determines what its most important feature is. (In many languages, paradigms announce their arrival like a sitcom character, pausing for applause and dominating the scene. They don't work as an ensemble, where they would simply pick up roles when needed.)
This often isn't clear to newcomers, because vocal users tend to project their personal beliefs heavily. Just as representatives of Earth would offer radically different perspectives to aliens. For example, Paul Graham dislikes OOP and iteration. So he never talks about it. But he seems to like functional programming, lists and macros, giving his audience the impression of that Common Lisp bias.
So you don't need to understand it very intellectually, unless you enjoy that. Program-is-data just lets you operate on code with the same muscles trained for data-handling. There are other things within Lisp that people don't mention, and are potentially more interesting. My operational definition of Lisp is of a system which invites you in. With reasonable defaults, in case you don't want to come deeply in.
You're right in that lists are very flexible and yet simple. And datastructures are so low-level that it's probably the best choice to take such a light cord and run with it. But I sometimes want data "associated" with code without having to look at it, like line numbers. If I'm writing a library which should give good error messages, I might want to emit line numbers. I think OOP may have a role here, so most code can be like it is today (lists, numbers, etc.), but I can also attach extra data onto a piece of code.
Type information (like x is an integer) could be another useful thing I don't want cluttering up my screen. Maybe my IDE can show x in a different color, and I can "rotate it in the 3rd dimension" to see the type info.
But maybe that's head-in-the-clouds dreaming, one of those things I wouldn't actually use. It's all up to experiment.
Lisp macros aren't defined that often. I'd guess the common usage is of other people's macros, which were debugged over decades. (Such as loop.)
Lisp macros allow community extensions to the tool. Maybe a more interesting, general point than simply claiming code-is-data as a wizzy feature.
RubyLanguage as an acceptable Lisp : http://www.randomhacks.net/articles/2005/12/03/why-ruby-is-an-acceptable-lisp
Lisp is not an acceptable Lisp : http://steve-yegge.blogspot.com/2006/04/lisp-is-not-acceptable-lisp.html
Quora Answer : Why have no modern languages taken the advanced concepts from the LISP ecosystem such as Scheme's continuations, the interchangeability of data and code, and Common LISP's REPL which can interrupt, examine, alter and continue code execution?
A lot of languages DO have REPLs. Python, Javascript, Ruby etc.
Ruby has continuations : Continuations in Ruby - Part 1: First Class Objects
Most languages that aren't Lisp have given up on homoiconicity (interchangable data and code) because they think that they get an advantage from having syntax.
But as others here are pointing out, there are some Lisps like Clojure and Racket etc. which are modern languages that stick to s-expressions.
Clojure, in particular, I think has a slightly different take on the interchange of code and data which has led to some exciting and valuable innovations.
But on the whole, most of the languages that love the Lisp concepts and ideas simply keep being dialects of Lisp. I think at one point Paul Graham even suggests that. By definition, a language that properly incorporates the Lisp goodness just IS a dialect of Lisp.
So will there be more Lisps in future?
Certainly? There's a whole new family of Clojure offshoots, from Hy to Ferret and Carp etc. Not to mention Clojure moving to new platforms. Racket is still a live project, although I'm slightly concerned that "Rhombus" seems to be a discussion about changing the s-expression based nature of it.
There are plenty of other Lisps and schemes around. Shen looks fascinating.
The Lisp tradition is very much with us today.
Quora Answer : Can Clojure eventually replace Common Lisp? What are the problems with Clojure that Common Lisp purists normally complain about? As Clojure matures/evolves, could it eventually serve as a model for an update to the ANSI Common Lisp standard?
There's too much politics and history for the ANSI CL standard to ever become Clojure.
What I think is much more plausible and I hope we will see, one of these days, is a proper native Clojure compiler and ecosystem. Which will let people write the same kinds of software (not JVM, not browser) that they write in CL, in Clojure.
Maybe if a native Clojure and CL could actually target the same binary object format, so that you could call from one to the other, this would be great for both communities.
I'd also, myself, like to see the Rackjure type projects finally give us a full Clojure-like experience on Racket.
Racket is meant to be a general purpose platform for building other languages on top of it which can interact with other Racket DSLs. In a sense, building a proper Clojure which lives on top of Racket and interops with it, should be the acid test of the Racket philosophy.
Update (after 20 people upvoted, can't assume they agree to this update) :
I've been reading and thinking a bit more about CL recently.
One thing I very much like about Clojure is EDN. The fact that you have a richer vocabulary for complex data literals that still follows the ideal that code and data are the same (so Clojure code IS just EDN data)
So I wonder, even if you didn't replace CL with Clojure, could you migrate CL to EDN? Basically use EDN as the syntactic substrate for CL. As EDN seems to be a superset of the existing (minimal) syntax of Lisp I guess moving to EDN wouldn't break backward compatibility with existing code. And the data-structures for vector and map could be mapped to their CL standard library equivalents.
Quora Answer : Why did Rich Hickey betray Lisp by creating a schism through his promotion of Clojure?
What's with this obsession with loyalty and betrayal and purity? And trying to diss Hickey?
These are meaningless ideas in relation to programming languages. We don't need them in our communities.
If anything Clojure has reinvigorated interest in Lisp.
I played with Lisp on and off for a few years. I read Paul Graham and thought it sounded like a wonderful thing. But never actually sat down and used it for anything.
Until one day I wanted to do something, thought ... hmm ... maybe I'll try this Clojure thing everyone is talking about (this was 2014), and within a week was hooked.
Now Clojure is my favourite language. But I've now also gone back to look at Racket. And started paying attention to Shen. And looked into other Clojure-likes like Carp. I'm more sold on Lisp than ever, after Clojure.
Though certainly, Clojure is my preferred type of Lisp. Which I think has great modern features.
But Hickey didn't owe anything to older Lisps. He hasn't "betrayed" them any more than the inventors of C "betrayed" BCPL. Or the inventors of Java betrayed C++
Building on existing good ideas but going beyond them is the essence of creativity and innovation and progress.
Quora Answer : What is your favourite dialect of Lisp, and why?
Clojure.
I think it's the best programming language I've met.
Not that it doesn't have flaws. But in terms of a sweet spot combination of power / elegance / practicality and ease of getting stuff done, nothing else comes close.
The only other Lisp I've looked at seriously is Racket. And I thought it was great. But for me some of Clojure's design decisions and the general well-thought-outness of things beats Racket. (See Phil Jones (He / Him)'s answer to How does Racket compare to Clojure? for more details)
I've played with other toy Lisps. Which were fun but not practical.
I've never looked into Common Lisp. My hunch is that it's probably quite like Clojure (Clojure is modelled on it, as I understand) But unlike Vladislav Zorov I've decided I like Clojure pushing me towards doing the proper functional thing so CL's multi-paradigm nature isn't something that attracts me. I also like Clojure's syntax tweaks and EDN for representing data. Clojure's focus on data is its secret (or at least, not so obvious at first) super-power.
Quora Answer : Why does Lisp have many variants? We do not really see this in other standard programming languages like Java.
Lisp is very old.
So it dated from the paleo age of programming languages, where different universities wrote their own language variations as research projects. And obviously were using new Lisps to add experimental features ... some of which, like scoping rules, actually change the semantics of the language.
Then it had a phase of being hot in the high age of proprietary software, during the 80s. Where multiple companies made Lisps as competitive commercial products.
Most of the languages we use today ... (Java is a non-standard case, but Python, Perl, Javascript, Ruby etc.) ... were developed largely as free-software, so there was no temptation to fork them. All interested parties contributed to the same project and code base. There was little incentive to fork.
Languages from the proprietary age tended to have multiple versions from multiple vendors. Each with subtly different features as they tried to outdo their rivals. This wasn't only true of Lisp. It's also true of Fortrans, and Cobols and BASICs and Smalltalks and commercial Pascals etc.
And then there were committees that tried to create standards that would bring different vendors to support a common subset.
The most successful standardization seems to have worked for C / C++. These languages have active standards bodies that churn out new standards every 10 - 20 years, and all versions tend to follow the standard. Other languages have fared more or less well. BASICs never got standardized in the same way. And the most popular BASIC, Microsoft's VB continued to get transformed according to Microsoft's goals until it became nothing like traditional BASIC or those from rival vendors, but what seems like a thin alternative syntax for Microsoft's C#. (Caveat, it's a while since I used VB so I may be exaggerating.)
Lisp did have a standards drive in the 80s, and this is what produced Common Lisp, an attempt to standardize what different commercial vendors were doing at the time. However, Lisp had also spun-off a new light-weight, stripped down academic research variant known as Scheme which also became popular in academia and theoretic computer science. Although people call Scheme "Lisp" in some ways the name is meant to distinguish it from Lisps.
One of the biggest, most popular Scheme variants, PLT, again decided that it wanted to evolve the language sufficiently far from other Schemes, that it chose to rename. Hence, we now have Racket.
Meanwhile, CommonLisp does seem to have been a fairly reliable, stable standard since the 90s. I'm not a CL programmer, and I'm not in or following that community, so I can't say much about it. But I haven't heard of any forks and variants coming out of it.
Finally, there's Clojure. A Lisp designed to work on the Java Virtual Machine and to play well with the Java ecosystem of libraries and in the Enterprise / mainstream software world. It has some design decisions which are constrained by those requirements.
It seems that the three big Lisp families these days are CommonLisp, Clojure and Scheme / Racket. These are different enough that we can't really imagine them becoming reunified, though we see quite a lot of influence where a library or idiom from one is adopted by another. Eg. Typed Clojure is highly influenced by Typed Racket. And Racket is adopting a library that puts all sequence types behind a common API, something which is one of the great pleasures of Clojure.
Quora Answer : Is there a positive example of something you cannot do in Lisp that you can do in any another language?
In most languages you can do the same things. But in some languages it's easier / more straightforward / more elegant to express what you want the computer to do, than in others.
Lisp is a very expressive language, and it's hard to think of another language that beats it.
There's no computation that can't be expressed in Lisp. And can't be expressed extremely well.
But as I point out in Phil Jones (He / Him)'s answer to If Clojure is one of the most expressive languages of today and has similar expressive power as Common Lisp, which goes back to early 80s, can we say that the field of programming languages hasn't progressed much in the last 40 years? other languages can score over Lisp, but not in expressing computation.
Where some other languages have an edge it's in expressing either constraints and invariants (types, contracts etc.), or expressing data-structures and architectural relationships.
Why does Lisp have many variants? We do not really see this in other standard programming languages like Java.
Lisp is very old.
So it dated from the paleo age of programming languages, where different universities wrote their own language variations as research projects. And obviously were using new Lisps to add experimental features \xe2\x80\xa6 some of which, like scoping rules, actually change the semantics of the language.
Then it had a phase of being hot in the high age of proprietary software, during the 80s. Where multiple companies made Lisps as competitive commercial products.
Most of the languages we use today \xe2\x80\xa6 (Java is a non-standard case, but Python, Perl, Javascript, Ruby etc.) \xe2\x80\xa6 were developed largely as free-software, so there was no temptation to fork them. All interested parties contributed to the same project and code base. There was little incentive to fork.
Languages from the proprietary age tended to have multiple versions from multiple vendors. Each with subtly different features as they tried to outdo their rivals. This wasn't only true of Lisp. It's also true of Fortrans, and Cobols and BASICs and Smalltalks and commercial Pascals etc.
And then there were committees that tried to create standards that would bring different vendors to support a common subset.
The most successful standardization seems to have worked for C / C++. These languages have active standards bodies that churn out new standards every 10\xe2\x80\x9320 years, and all versions tend to follow the standard. Other languages have fared more or less well. BASICs never got standardized in the same way. And the most popular BASIC, Microsoft's VB continued to get transformed according to Microsoft's goals until it became nothing like traditional BASIC or those from rival vendors, but what seems like a thin alternative syntax for Microsoft's C#. (Caveat, it's a while since I used VB so I may be exaggerating.)
Lisp did have a standards drive in the 80s, and this is what produced Common Lisp, an attempt to standardize what different commercial vendors were doing at the time. However, Lisp had also spun-off a new light-weight, stripped down academic research variant known as Scheme which also became popular in academia and theoretic computer science. Although people call Scheme "Lisp" in some ways the name is meant to distinguish it from Lisps.
One of the biggest, most popular Scheme variants, PLT, again decided that it wanted to evolve the language sufficiently far from other Schemes, that it chose to rename. Hence, we now have Racket.
Meanwhile, CommonLisp does seem to have been a fairly reliable, stable standard since the 90s. I'm not a CL programmer, and I'm not in or following that community, so I can't say much about it. But I haven't heard of any forks and variants coming out of it.
Finally, there's Clojure. A Lisp designed to work on the Java Virtual Machine and to play well with the Java ecosystem of libraries and in the Enterprise / mainstream software world. It has some design decisions which are constrained by those requirements.
It seems that the three big Lisp families these days are CommonLisp, Clojure and Scheme / Racket. These are different enough that we can't really imagine them becoming reunified, though we see quite a lot of influence where a library or idiom from one is adopted by another. Eg. Typed Clojure is highly influenced by Typed Racket. And Racket is adopting a library that puts all sequence types behind a common API, something which is one of the great pleasures of Clojure.
Quora Answer : What is the future of the LISP programming language?
I'm writing this answer as an unabashed Clojure fanboi.
I hope that the Lisp community recognise what I think are the two big advantages that Clojure brings to Lisp. And that future Lisp family languages keep them and build on them.
The first of these advantages is immutability. Most FP languages go hard for immutability (it's more or less the essence of FP). But for historical reasons Lisps have tried to sell themselves to a wider public on being "multi-paradigm" and so have been tolerant of mutable state.
I'm a fan of immutability though (Phil Jones (He / Him)'s answer to In your experience, are immutable data structures and paradigms easier or harder to understand in general (and especially for newcomers) than regular imperative mutable programming paradigms? Why?) and I hope very much that we'll see both growth in Clojure. But also newer Lisps will follow its lead in restricting state to very specific mechanisms like "atoms" etc.
The second of these advantages is syntax for data-structures.
As I've mentioned elsewhere ( Phil Jones (He / Him)'s answer to If Clojure is one of the most expressive languages of today and has similar expressive power as Common Lisp, which goes back to early 80s, can we say that the field of programming languages hasn't progressed much in the last 40 years?) representing "computation" is a solved problem in programming languages. And Lisp's minimal syntax is just fine for it. But there is scope for better representation of data. And I believe that Clojure's EDN demonstrates that it is worth trading the cost of a little bit of extra syntax, in return for better ways to express complex data literals in our programs.
Today, for anyone thinking of inventing a new Lisp, I would strongly urge them to adopt both of these features from Clojure. Build the language on EDN with the vectors and maps and keywords standard along with the usual parentheses for list syntax. Implement these standard data structures as immutable. And restrict mutable state with specific mechanisms like atoms and refs.
Now, if you read that second answer linked above, about expressivity, you'll know I have some further opinions about language design. And syntax for representing data, architecture and constraints.
I'm very ambivalent about static typing. I tend to be in the dynamic typing, not caring much for static types camp. With occasional visits to the "OMG I wish I had a way of setting and testing type constraints on this mess" camp.
Clojure has Spec. Which I think has both some good features. And some features I can't get on with.
Two developments that interest me greatly are Shen Language and Carp Lang
Shen is a Lisp that adds a powerful type checker. One which is almost a kind of Prolog-like inference engine.
Carp is an interesting mix of Clojure syntax, but with low level memory management inspired by Rust (a borrow checker). And a type system with type inference that's more like the ML family of languages than a Lisp. It has these features because it's aimed at writing low-level code for embedded systems, games and audio applications etc.
But one thing that distinguishes it is that it has, what looks to me, the nicest, most Lispish and convenient way to add type checking I've seen in a Lisp. You wrap any expression with what's effectively a compile time assert that the expression result is of a particular type.
So you write something like :
(defn f [x y]
(the int
(+ x y)))
That's it. You've typed the expression (+ x y) as having to return an int. (That's what (the int sexp) does. )
And then type inference lets that constraint percolate through. Eg. it recognises that the arguments x and y must be ints and the return value of the function will be one.
This feels right to me in a way that other optional / gradual type-checking in Lisp doesn't. Maybe I just don't get it, but Spec comes across as the opposite of Clojure's usual elegance of beautiful design. It's ugly and clunky.
There are definitely days I dream of "the next Clojure" (ie. the next step forward in Lisp) which is like Clojure except that Spec has become as powerful as Shen, and as elegantly easy to slot into existing code as Carp. With compile-time checking.)
Quora Answer : What would it take to unite Common Lisp, Scheme, and Clojure into a single universal Lisp?
It would be very hard because these languages have quite different semantics that are inconsistent. And because the Lisp syntax is so minimal, the semantics counts far more than the syntax.
You can't just kludge together a language with default mutability and Clojure's default immutability and have something that's greater than the sum of the parts.
However, what you might hope for is something more like the Racket approach, where modules in different languages could compile to the same underlying object code and interoperate.
Even that is still hard, because an important part of each language is its standard library. The Clojure standard library of immutable vectors and maps is so important to it that the language even adds extra syntax to support them.
From what I've seen of Racket. And what I imagine of Common Lisp, both would benefit from the addition of good immutable vectors and maps in the standard library. And even benefit from adding Clojure-like syntax.
BUT ...
this would be a major rupture with the existing libraries these languages use. And I don't imagine for a moment that existing Racket, Scheme or CL programmers welcoming being asked to throw away their existing solutions for vectors and maps just to use the Clojure ones.
So even if you have different modules in different languages that can compile to the same underlying object code and call each other, you still have the problem of what data-structures can be shared between them.
Are they Clojure immutable structures? Or mutable ones.
Clojure can use mutable data-structures written in Java, of course. But Clojure is based on Java. So the interfaces to both are very similar. What would happen if Clojure modules tried to use a CL module with a mutable vector and an API that reflected that? It could work, but it would stop being very much like Clojure code.
But it's not impossible. One odd feature of Clojure is that it IS intended to be "on top of" to interop with another language and isn't too bothered about letting some of the underlying language come through.
So I could imagine someone inventing a Clojure which compiled to Common Lisp or CL compatible binary files and allowed interop with existing CL libraries and code-bases.
There would be some advantages to that. Clojure programmers are looking for a "compile to native" solution. So if it provided a viable compile to native solution, then I think we'd be interested. And I think at least some CL programmers would welcome being able to use Clojure.
Similarly, I think a good test of Racket's "programmable programming language" capacities would be if someone could implement a Clojure language on that. Rackjure is not syntactically compatible with Clojure. It's just a version of Racket that is bit Clojure-flavoured. But I'm not sure that's been "good enough" for anyone to be really interested.
But a fully syntax compatible Clojure as a Racket hosted language, would be interesting.
Obviously you'd have to support Clojure's vectors and maps which are hard-wired into the syntax, and some of the standard Clojure library. But this is not an insurmountable problem. Again, I could see advantages to it.
Given that Clojure has "reader conditionals" in CLJC files, that let you put in bits of code specific to the underlying language, it might even be possible to use this mechanism to write Clojure libraries that could be compiled to Java, Javascript, CL-compatible binary or Racket. And that expanded version of Clojure could become a viable option for CL and Racket users too.
That "sideways" way of bringing Clojure as an option to the CL and Racket ecosystems is probably more feasible than some committee trying to bring them all together.
Backlinks (44 items)
- BEACH
- BareMetal
- BlubLanguage
- CatHerding
- ClojureLanguage
- ConstructSubLanguagesDynamically
- CostsBenefitsOfMetaProgramming
- DavidNoble
- EmacsLisp
- FernandoBorretti
- ForspLanguage
- FunctionalProgramming
- HeliotropeLanguage
- IdealProgrammingLanguage
- IntentionalProgramming
- JonesFirstLawOfWiki
- KernelLanguage
- LanguageOrientedProgramming
- LispAndAI
- LispAsATrainSet
- LispFromNothing
- LispInLife
- LispOnGPU
- MicroLisp
- MindTrafficControl
- NewLisp
- OnLisp
- Patterning
- PaulGraham
- PharenLanguage
- PlatformWarsPhilsInterests
- ProgrammingLanguages
- PrologAndLisp
- Quines
- RacketLanguage
- SchemeLanguage
- ShLisp
- ShenLisp
- SubText
- TheCostOfSyntax
- TheLibraryProgramBoundary
- Thingamy
- UserInterfaceStuff
- WispLanguage