2. The data is also list, and your program is also a list.
3. Algorithm are basically List Manipulation(Stacks, Queues, Trees, Adjacency lists). So its easy to write complex algorithms in Lisp.
4. Tail call recursion. This part amplifies 3. further.
5. Functional programming features.
6. REPL. I mean like a real REPL.
7. Macros.
1 - 7 helps you to express problems and their solutions with code which represents exactly that. The boiler plate and other assisting code is largely non existent.
Another reason is if a thing has been there around for the longest, more people have thought about it. Both quality and quantity of literature of it are higher than others.
Being older doesn’t necessarily mean either quantity or quality of literature will be greater. MUMPS has been around for much longer than Go, for example.
For example, it is a homoiconic language, so any piece of data can be evaluated as if it is code.
The only way to really understand it is probably to learn it :)
Ironically modern Javascript often replicates the bracket pileup, just with "})" instead. Python does away with it by having "nonindented newline" as an invisible semantic character that closes any number of scopes.
You said:
> ... the single representation carries little structural information and the meaning of a symbol is highly dependent on its containing context.
That makes me wonder if the difference is abstract vs. concrete thinking - those who by nature prefer abstract thinking will find Lisp more natural, and those who prefer concrete thinking will find it clumsy and unsettling.
Choosing the "right" programming language is not just finding the right language for the task (though it is that). It's also finding the right language that fits our minds - and our minds are not identical.
I started with BASIC, various Assembler variants, PASCAL, UCSD PASCAL, MODULA 2, ... and then learned Lisp variants and Scheme - and also learned basics of some other languages like ObjectPascal, SAIL, Prolog, Postscript, Smalltalk, ...
That being a problem is pretty much solved by not writing 1000 line top-level expressions with thirty nesting levels.
People who actually write Lisp are engaging their imagination for the program itself. Thus their imagination is too busy to come up with scary reasons how things could go wrong that would spook them out of continuing.
Most of the time a Lisp programmer wants to read WHAT the program does and that in a very descriptive notation.
Any Lisp has a lot of macros. The base Common Lisp language is full of macros. Any defining operator - functions, macros, variables, classes, structures, methods, ... - is already a macro.
For example a structure - a record - is defined like this:
(defstruct ship
(x-position 0.0 :type short-float)
(y-position 0.0 :type short-float)
(x-velocity 0.0 :type short-float)
(y-velocity 0.0 :type short-float)
(mass *default-ship-mass* :type short-float :read-only t))
This is using the macro DEFSTRUCT.It's easy to see that it defines a structure type called SHIP with 5 slots. Each slot has a default value and named options.
A programmer will NEVER need to see what the expansion looks like. The code the macro generates is twenty times larger than the source code. What the programmer actually needs is a documentation of what effects the macro has: defining a type, defining accessors for the slot, defining a type constraint for the slots, making one slot read only, ... This is better read from the documentation of this macro operator, instead of trying to see it from reading low-level operator code implementing them.
Every programmer will be happy to read this macro form - no one wants to see the expanded code, how structures are actually defined in terms of low-level operators.
Thus MACROS increase the readability of programs a lot - independent of the team size. Really no one would want to define a structure type by manually creating all the definitions for it (a type, an allocation function, slot accessors, type predicate, compile time effects, ...).
What they can make more difficult is some maintenance tasks - where bugs appear on a meta-level where programs transform code.
(It's a bizarre, mini language for looping constructions and terrifying animals and small children.)
(loop for i from 10 upto 20
do (print i))
what does it do? Maybe it prints the numbers from 10 upto 20? (loop for element across vector
sum element)
Hmm, what does it do? Maybe it sums all the elements of a vector?Ada:
for E of The_List loop
if Is_Prime(E.P) then
E.Q := E.Q + X;
end if;
end loop;
Lisp: (loop for e in the-list
if (primep (p e))
do (incf (e q) x))
Totally weird and bizarre how it looks similar.Even stranger:
(
loop for e in the-list
if (primep (p e))
do (incf (e q) x)
; end if
; end loop
)The basic idea comes actually from Interlisp and Warren Teitelman‘s ‚Conversational Lisp‘ and its FOR macro.
The main purpose of LOOP is to question ones assumption what is Lispy and what not. ;-)
The paper from 1980 on 'LOOP Iteration Macro' by Burke&Moon does not mention him at all.
Yeah, I might be misremembering.
I still feel current generation of programmers has a learning phobia.
And that's in Scheme, so it doesn't look like someone dropped a chunk of Algol in your coffee.
(I don't know lisp) but sometimes this approach just makes the code really difficult to understand afterwards. Does Lisp have something that makes it easier or better?
[1] Credit where due - I stole that phrase from my friend Michael Pavlinch.
I don't think Lisp is much more difficult to like, on the contrary, out of all the languages I know well (C, C++, Python, Java, Common Lisp) not only do I find CL _by far_ the easiest to write but also that it puts me in a state of flow (= unparalleled mental clarity, focus and productivity) which doesn't easily happen with the others.
Credentials: I spent close to 10 years writing C++ at Google.
I certainly think that Lisp is very different to most popular programming languages today and that difference is immediately obvious. This makes it very easy for people who do not like leaving their comfort zone to dismiss Lisp simply because it "feels" too strange to what they're already familiar with.
- Structural simplicity. Instead of having a huge mess of syntax to keep track of, it has only a very small number of constructs. Simplicity is beautiful.
Criticizing it on the basis of parenthesis would be roughly equivalent to criticizing someone talking about the beauty of mathematics on the basis of the color of the piece of chalk they're using. It's true that it's criticism about aesthetics, but it's not criticism about the aesthetics that the mathematician was talking about.
Once you've understood in what sense people mean that Lisp is beautiful, you can disagree, but this disagreement will not concern parentheses.
As an aside: I have a similarly shallow aesthetic aversion to JS syntax for the same reason. When I encounter a 12-line ragged cascade of curly brackets, square brackets and parentheses, sprinkled with semicolons, I wonder how that can be considered OK.
Aside 2: with Lisp, you edit programs structurally, meaning that their position is essentially managed for you. This is what people refer to when they mean that "the brackets disappear after a while." You're not focusing on them; they're handled by something else.
In my editor, I have the closing brackets faded nearly into the background, which reflects how concerned I am about their existence.
It's considered OK because the extra syntax carries semantic weight, and the semicolons disambiguate intent for the interpreter (because while semicolons are optional in javascript, leaving them out can lead to errors.)
And as someone just beginning to play around with (Arc) Lisp, I still can appreciate both paradigms. Neither is objectively wrong.
Which is a very roundabout way of saying that JavaScript has a very complicated grammar. Is it necessary? No, it isn't. People use and love languages with much simpler grammars, such as FORTH (reverse Polish notation), APL (monadic and dyadic algebraic notation), and Lisp (fully parenthesized Polish notation).
If you think Javascript's grammar is "very complicated" then C++ will probably give you a heart attack.
You're overstating what amounts to an aesthetic argument, which is fine, but not really compelling.
I'm not sure this is a great presumption. Someone can be familiar with lisps, understand the design choices involved, even deeply appretiate the beauty of the resulting language, while still prefering languages with a more flexible syntax
> This is what people refer to when they mean that "the brackets disappear after a while." You're not focusing on them; they're handled by something else.
This is exactly the problem. Lisps surrender the issue of syntax completely to the interpreter/compiler, which makes it easy for a machine to parse, but harder for a human. I personally prefer syntax to be designed for humans to read and write, because its going to be translated to something different to be executed anyway.
Now, the simplicity of the lisp syntax is of course intimately connected to the homoiconicity of the language and the extremely powerful macros, so I do understand the value of it and the tradeoffs involved. (Although I find it slightly ironic how it's venerated, given that the original lisp actually had two syntaxes, M-expressions for the human to manipulate and S-expressions for the machine to manipulate).
I personally prefer to do my "meta-programming" in the type-system and have flexible syntax to express functions in different ways relevant to the uses of the language. That can be Elm with it's simple type system and elegant operators for application (|> and <|) and composition (>> and <<) which indicate direction, or it can be Agda with it's unicode syntax and custom mixfix operators, where you can define a if-then-else as a function as "if_then_else_ : (b : Bool) -> (x : a) -> (y : a) -> a" and call it "if <b> then <x> else <y>". I find that the way these languages use operators, reduces the need for parenthesis and allows you to express what your code is doing, whether it's a pipeline of functions or some imperative-like steps being done in order. The result is a syntax that I find clearer.
I am however, well aware that a lot of people dislike Haskell's use of operators and that these languages are a minority in terms of usage indicating that my preference might not be common, but I don't necessarily presume that it's because they don't understand Haskell.
That is a naive fallacy. What is harder for the machine is harder for the human.
By and large, humans rely on formatting cues, especially indentation, to parse programs. Human eyes can be fooled fooled by bad indentation:
/* C */
if (foo)
bar();
cleanup();
if (outer)
if (inner)
foo();
else
bar();
If you want to compare human versus machine parsing, then you need to write all the code samples on a single line with no breaks (if the programming language allows that). All optional whitespaces that can be written as a single space should so be written. This way, the humans are actually parsing the same tokens as the machine and not relying on cues that aren't part of the language.> I personally prefer syntax to be designed for humans to read and write
There is no such thing in existence. People who design syntax simply use their whims, rather than any cognitive science that brings in any measure of objectivity. Those whims are shaped by what those people have used before.
The concept behind Python is actually the closest to getting it right: it recognizes that people really grok indentation rather than phrase structure, and so it codifies that indentation as the phrase structure.
> Languages are a minority in terms of usage indicating that my preference might not be common
That's another fallacy. The vast majority of all programming and other computing languages that have ever been invented are not used at all, or used by a vast minority. In that vast majority, we can find the full gamut of what has been done with syntax, semantics and everything else. Popularity and lack thereof isn't trivially driven by cosmetics.
No, I'm not claiming an essential difference, merly that they are optimized for different things.
>There is no such thing in existence.
Of course there is, machine code is designed for computers, higher level languges are designed for humans.
>Popularity and lack thereof isn't trivially driven by cosmetics.
I'm not talking about what drives popularity, but what drives cosmetics.
(Machine programs are hard to understand, but in this area we don't have an easy human to machine comparison: machines generally don't understand programs. The advantage of machine language is that it doesn't have to be understood in order to be efficiently executed.)
Yes, you can, but re-read the original comment: the implication was "how can it be beautiful with all those parentheses?" It seems clear that two different aspects of beauty were conflated.
> …what is it about the "beauty" of Lisp that the HN community seems to like so much? … the number of parentheses is just mind boggling. I want to understand why it is so loved.
Also, I would love to hear which language(s) has a more flexible syntax than Lisp, seeing as expressiveness is one of Lisp's strong points.
> Lisps surrender the issue of syntax completely to the interpreter/compiler, which makes it easy for a machine to parse, but harder for a human.
What does "surrender the issue of syntax" mean?
In any case, citation needed for this one. "Easy" and "hard" are very strongly dependent on familiarity. This human finds them easy enough to parse.
> I find that the way these languages use operators, reduces the need for parenthesis and allows you to express what your code is doing, whether it's a pipeline of functions or some imperative-like steps being done in order.
Reducing parentheses is not really a strong selling point for someone familiar with Lisp, because Lisp programmers don't really work with parentheses like in other languages (again, they're managed).
It's not that they're liked for their own sake, but they enable many advantages (such as homoiconicity, structural editing, easy, selective evaluation of expressions at any level of nesting, and so on).
That being said, in Clojure, I often prefer to pipe functions like you mentioned when it seems like the expression would end up unnecessarily nested otherwise:
(-> 8 inc str vector)
;; => ["9"]I'm thinking about ML-like languages such as Elm, Haskell and Agda (to give a spectrum of examples with varying degrees of complexity in terms of language features).
> Lisps surrender the issue of syntax completely
I think I am referring to the same thing as you are when you say that they're not used like other languages, and that they are managed.
>This human finds them easy enough to parse
Easy enough is good, but I think we can do better!
> It's not that they're liked for their own sake, but they enable many advantages.
I think this is what I was trying to get at. :)
FWIW, I like lips a lot, and consider them far better than most mainstream languages.
It doesn't. It just works differently and looks different because Lisp syntax is defined on top of s-expressions. Lisp syntax is provided by built-in syntax for function calls, a bunch of special operators (let, progn, block, catch, quote, function, flet, if, ...) and a zillion macros. Each macro provides syntax - from primitive examples to complex syntax (the LOOP syntax is an example). The syntax is user-extensible by defining macros.
The level of s-expressions is a syntax for data. This syntax can be changed by readtables and readermacros.
Contrast this with most other languages, where there are many things the language does that you can not do. At least, not easily.
There aren't actually more parens in a Lisp program than a program written in a C-like syntax (which is really an algol-like syntax). They just stand out more for two reasons:
1. There is less punctuation in general, so the parens are more obvious. Instead of f(x, y, z) you write (f x y z). Without the commas, the parens stand out because that's all that is left.
2. There is only one kind of parens in Lisp whereas C-like languages use at least three: (), [], and {}, so that makes any particular kind of paren less prominent.
4. The lisp punctuation style closes all levels on a single line, where most C code guidelines close one level per line. This leads to a "thick" chunk of close parens that students of lisp find harder to read at first.
Well put, Madam/Sir.
No, instead you get something like );}]);) except that that's usually split up over several lines.
BTW, it's pretty easy to tweak Lisp's syntax so that your parens don't get so deeply nested. See
https://github.com/rongarret/tweetnacl/blob/master/ratchet.l...
for an example.
1. Other languages have operators which can be written without brackets, x + y vs (+ x y).
2. Precedence rules allow ex. polynomial expressions to be written without brackets, 2 * x + y vs (+ (* 2 x) y).
3. Algol-like let-bindings or monadic-do-style variable-bindings that inject bindings into the containing block (as opposed to Lisp-style let-blocks where the new scope typically corresponds to a new block) use fewer brackets and keep nesting depth smaller.
# 2 sets of brackets
fun foo(x, y, z) {
let w = x + y;
let u = w + 2*z;
let v = w - 2*z;
u * v
}
# 13 sets of brackets
(fun foo (x y z)
(let ((w (+ x y))
(u (+ w (* 2 z)))
(v (- w (* 2 z))))
(* u v)))http://www.flownet.com/gat/lisp/parcil.lisp
See:
http://www.flownet.com/gat/lisp/djbec.lisp
for some example code that uses this parser. Scroll down about half way and take a look at xpt-add and xpt-double.
((+ ((* 2 x)) y))
"I have this sublanguage..." is not a very interesting participant in the evidence that Lisp doesn't have lots of parens.I'm still fond of Lisp, but languages like Python, D, Nim (and increasingly, Rust) offer a lot of the Lisp affordances that I really valued -- in particular, easy compile-time metaprogramming. The biggest missing bits are Lisp's deeply integrated REPL-driven programming, and the use of program images -- which have many drawbacks but also some benefits.
IMO, everyone should write and maintain a medium-sized program in a modern Lisp (SBCL, CCL) at least once, just to get an appreciation for how different the programming / debugging experience is. So many well-integrated tools at your disposal, even at runtime.
Lisp (or Scheme, in this case) is a very simple language that gets essentially everything right.
I have to wonder if you actually know all that much about Scheme. Undelimited continuations, for example, are pretty much strictly broken. I like Scheme, but to claim it's flawless is kinda ridiculous.
As far as syntax goes, the proof is in the pudding. All languages have people gripe about some part of their syntax or another, but it's clear from experience that "OMG parentheses" is exceptionally prevalent. Hand-waving it away as something that people just don't get because of lack of prior exposure is not really sound - somehow other languages don't get similar complaints (at least, not as universally, and not to the same magnitude) with first-time users. Besides, why is there a lack of exposure? Why, because everything else is different. But why is it different? Isn't the obvious conclusion that Algol syntax family is vastly more prevalent for the simple reason that people prefer it, and simple homoiconicity is not sufficiently enticing?
All arguments in favor of Lisp syntax feel like they ultimately boil down to "you're holding it wrong". And that may well be so - but if so many people are finding it so awkward to hold, isn't that prima facie evidence of ergonomic deficiency? I don't claim to understand why Algol-style is easier. Maybe the way our visual processing works is just better with more varied punctuation? That's something for psychologists and brain scientists and maybe linguists to figure out. But in the meantime, we could at least acknowledge the way things are. I really like Lisp as a collection of ideas (not just the usual ones like HOF and macros, but also stuff like e.g. symbol-based namespacing, or the sheer flexibility of CLOS). But lispers have to ask themselves why, instead of Lisp seeing wider adoption, other languages - that came literally decades later, so "upstart" would be a very polite way to describe them in this context! - become vastly more successful than Lisp by appropriating its cherry-picked features.
That is just confusing cause and effect.
> All arguments in favor of Lisp syntax feel like they ultimately boil down to "you're holding it wrong". And that may well be so - but if so many people are finding it so awkward to hold, isn't that prima facie evidence of ergonomic deficiency?
You are confusing cause and effect again, this time by implying that there is something fixed about the way people learn languages (Chomsky's "language organ"). Learning is not like the shape of your hand.
Once you learn structured editing, Lisp code can be written and changed in much fewer keystrokes than code expressed in a more complicated grammar, which is actually ergonomic.
And what is the evidence to that claim?
I'll grant you that I haven't given any evidence for my claim, either. But, again, the onus is on those claiming that syntax doesn't matter to prove so, against overwhelming practical evidence (showcased by user count) that it does.
So many computing languages have come and gone over the years; the number that have been created vastly outnumber those that have ever been popular, let alone that are now popular.
Lisp is amazingly vibrant as a family. People are still excited about it and there is development work going on. That's amazing for something with such old roots.
I added two instructions to the virtual machine this morning, and used them in the compiler of a Lisp dialect to eke out a little performance gain. Wo hoo!
The haters can all go stuff it.
Of course they are not. If you put on a shoe, and it's uncomfortable, you just go get a better shoe that is. This does not negate the validity of the question: why was the first shoe uncomfortable?
You seem to think that popularity should be the prime consideration when it comes to programming language design. This is what gave us PHP and Javascript. I dare say that the people that use Lisp today (and there are plenty of those) do so because nothing else will be as good to them. They love the language. I've known people who moved jobs and got less money in order to work with Lisp. What does that say about the language?
OTOH distinctions like expressions vs statements don't apply -- my years as a lisp developer were the most productive of my life.