Gaaah, knock off the CAPSLOCK and the machismo, please.
Also, you don't need to invent backcronyms for CAR/CDR, they're now called first/rest.
Having said that, I really like the presentation of your blog, nice typography. And after skimming your book[1] in progress, and noting your obvious theoretical bent and taste for rigor, I can only anticipate to read more of your future posts (latch on to something "obscure" like ACL2 and make something fun with it.)
The book has code samples in 4 different languages; LISP (the ancient cap-cased "one"), ML, C, and what looks like Pascal. If you want to learn about the axiomatic specification of computer programs, specially for "structured" programming, then look into the works of Gries and others, specially in the silver "Texts and Monographs In Computer Science" books (the entire series is a feast of delight that should be devoured, and washed down with heirloom, stolen wine):
The Science of Programming, Gries.
The Design of Well-Structured and Correct Programs, Alagic and Arbib.
The selection Programming Methodology edited by Gries has various approaches to the structured method, with contributions from Dijkstra, Hoare, Wirth, Reynolds and other rock-stars of axiomatic semantics and verification.]
This is where I'll refer people who know nothing about Lisp when they complain about it; not too self-righteous, pleasantly informative, and theoretically interesting.
Or e.g. cadaadr -> frffrst, "first of rest of first of first of rest of" . I don't know if any Lisp uses composed first/rest that way, but if I were implementing a new Lisp from scratch I would probably use that rather than car / cdr.
(I prefer pattern matching / destructuring-bind, though.)
Maybe im to inexperienced with classic lisps, or maybe im just spoiled by clojure, but i have no idea what cadadr means, is it the rest of the first, of the rest of the first, or the other way around?
For things like cadadr, I just chop off the "c" and "r", and use the middle part to figure out the sequence of car and cdr calls. (cADADr x) = (cAr (cDr (cAr (cDr x)))), which would be (first (rest (first (rest x)))) in Clojure.
I suppose CL/Scheme programmers just learn by heart what those combinations do (ie. what kind of structure they work with), because to me both cadadr and the (first (rest ...)) sequence are equally meaningless at first glance. It's not easy to see what the data structure looks like.
In Clojure it's usually more idiomatic to use destructuring, which I think is much more understandable since the form follows the structure that is being accessed.
Or you can use get-in, which takes a sequence of keys to dig into a deep associative data structure. It doesn't work with sequences, but building highly nested seqs is rather uncommon in Clojure.
In practice, I don't find it has many more parens or angle-brackets than, say, C++ or Java. Considering (), {}, and <> in those two languages, I'd bet Lisp wins.
Languages with juxtaposed argument application (Haskell, OCaml) and meaningful indentation (Python, Haskell) will win over Lisp. Mixfix-based languages like Agda2 or Maude will win even more.
And fail spectacularly - they have to introduce special "invisible apply" operator to make Haskell to be closer to imperative languages, just to do not look like they are cheating.
This is attributed to juxtaposition as application (as it reduces number of lexems) and to definition of functions by pattern matching. I think other languages with those two features would have same effect over predictive force of Halstead metric.
I spent maybe five years being paid to write Lisp code in the early '90s and I can remember what a lot of the code looked like and, just your like that image, I really don't recall the parens that distinctly.
Anyone manage to build a Lisp that used semantic indentation (like Python)? You could make it optional and just have it function as a preprocessor that generates the real thing.
It hides the parentheses, and emacs by default will indent your lisp correctly. Just like the real thing (except you can't edit while in UnParenMode...minor issue).
I do enjoy the irony in commenting with "can we get rid of the paretheses" on a post explaining why the parentheses are not important. When you truly understand lisp, you will no longer see the parentheses. They aren't real.
I find this amusing because I've always found "lisp has too many parenthesis" and "python has too much significant whitespace" to be roughly equivalent in terms of relevance.
Nobody writes tools that randomly shred parentheses, but this happens all the time with whitespace. I'm halfway convinced Ruby is encroaching on Python because you can't really talk about the latter on the web without ridiculous workarounds.
How so? I suppose if you paste Python code in a comment box that happens to eat whitespace, then there is a problem, yes... but for those cases there's pastebin and such. Other than that, if you're writing a blog post or article, then you can just slap the Python code in <pre> blocks, which preserves the whitespace; most "humane" text editing formats like Textile and Markdown have ways to preserve it as well.
In my experience, that's easily 2/3 of the web and half of all email and IM clients. It was so bad that I was surprised when it didn't fail somehow.
Pastebin is just the kind of workaround I would hate to be consigned to. Reading offline or printing becomes a huge headache because important details are constantly missing.
One thing that bothers me about Python's whitespace, is that it is not possible automatically indent Python code that has lost its indentation for some reason or another. You have to go back and read the original source to restore the meaning of the program even though you already have all the visible tokens it contains.
Are you kidding? Mandating whitespace is possibly the single worse feature of python. Lisp editing is an extremely mature topic, and rarely does a lisp programmer have to actually deal with code formatting. To turn that on it's head would be madness. A complete step backward.
You both have stupid arguments which basically boil down to "I don't like it because I prefer it the other way." This stupid flamewar has been fought countless times on countless online forums, let's not do this.
No... my argument is: "requiring lisp programmers to pay attemtion to formatting when they haven't had to do so for years, just to make some python developers feel more at home, is stupid."
Mandating whitespace complicates the situation, and for what benifit? You're the one proposing a dramatic change, show some dramatic evidence to back up your proposition.
Mandating whitespace complicates the situation, and for what benifit? You're the one proposing a dramatic change, show some dramatic evidence to back up your proposition.
What did you not understand by "let's not do this?"
> We can get rid of (or make optional) a lot of parentheses by making indentation significant. That's how programmers read code anyway: when indentation says one thing and delimiters say another, we go by the indentation. Treating indentation as significant would eliminate this common source of bugs as well as making programs shorter.
It's done automagically for me in Python and Haskell, too. Instead of hitting the paren keys in Emacs, I just hit tab to cycle through the possibilities.
Because the Lisps have such a canonical way to indent them, in practise it feels very similar to significant whitespace with a funny input method.
Normally, hitting tab just insert another \t wherever your cursor happens to be. Hitting tab in haskell-mode or python-mode just cycles through the two or three (or sometimes one) possibility for indentation for the current line. That's automagically enough for me.
Removing parentheses from the syntax removes the notion that lisp programs are lists of lists.
You can play around with significant whitespace all you like, but you have lost the simple representation of a list. How many hideous grammar hacks will you add to get this back?
"Dorsal" means "top", like where the dorsal fin on a fish is. It doesn't even remotely mean "everything except the front". (The belly of a fish is "ventral".)
Man all the hype about Lisp just suddenly made sense to me. Why do we need all this other stuff? Loved the simple exposition and backronyms, contrary to some other opinions here.
We definitely don't need all the fluff, and I like the philosophical cleanliness of Lisp (from a distance), but to me it seems like too basic of a building block to think with. Haskell's point free style and K's vector building blocks seem more useful to me for use in philosophical reasoning about algorithms.
Does anyone else have trouble with making the distinction between curly braces and parenthesis?
I'm pretty near sighted, so I always have to squint to figure out if something is a brace or a paren. I think it is one of the main reasons I like lisp...
There are no braces, and all I have to do is make sure that emacs indents everything properly (ctrl+alt+q at top of form... in my head I call it 'regrinding') so I know that the forms I've written have the closing parens in the proper places.
I know people complain about the parens, but I spend literally no time fudging with the formatting of my lisp code.. emacs just does it. Java and C code, however I always end up fiddling with (even with an 'advanced' IDE like eclipse).
Argument: "Lisp has too many parentheses. It's unreadable."
Response: "It's conceptually elegant that everything is parentheses."
This doesn't address the real point -- you can't read it well. You do get advantages for macros and symbolic processing. But the cost in readability is still there.
I've yet to find Lisp any more or less readable then anything else I write day-to-day (Python, Ruby, JavaScript, CSS, HTML). In all these languages I find myself constantly fighting to find a readable and reasonable formatting. I certainly won't argue that I find myself doing this less in Lisp, but the readability argument is just something that continues to be bandied about by people who haven't spent much time programming in Lisp.
That honestly looks more like a failure on the part of the Python library maintainer to create a pleasant way to create record prototypes.
I mean, all you're doing in your list example is creating dictionary and list examples of the mapping you want. There is literally nothing stopping you from doing that in Python.
Yes you could do something like this. But the lack of keywords does reintroduces some noise via the quotes around strings. Moving the colons around like this to give visual alignment would probably be frowned upon. So my sense is that this would be considered "un-Pythonic" but I could be wrong.
I certainly don't write Python code that looks like what I wrote. My point was that the various idiomatic versions, including yours, certainly isn't any more readable than the Clojure version.
I don't speak for everyone but the reason I see lisp code as unreadable is that most of what I've seen is written like your example. That is, there is some indentation which helps, but it's as-if the coder is afraid to utilise vertical space so they put all the closing brackets on the same line, most of the opening ones in the middle of some lines. With that kind of formatting (for me at-least), it's not immediately clear which.
I think the real point here—the one that half the article was spent in making—is that Lisp (the grammar that uses lots of parentheses) isn't the same as Lisp (the concept).
Lisp (the concept) isn't a language at all, as far as we use the term to describe something that humans can use to communicate information serially. Lisp is actually a model for representing a transformation of an AST as an AST—no more, and no less. To communicate a Lisp transformation model, we must encode it as a stream of characters—and that stream, if we don't do anything to make it readable, becomes the "degenerate case" of programming languages: pure S-expression syntax.
However, there's no need for Lisp and S-expressions to go hand-in-hand. For decades we've known that programming languages have UX considerations every bit as important as those of the programs made with them. Lisp precedes that realization, but even when Lisp was first invented, S-expressions were never intended to be its primary encoding (search "M-expressions".) It just turned out that Lisp was such a powerful model that it was immediately put to use before a nicer syntax could be wrapped around it. (Also, its core user-base were mathematicians, who already had the isomorphic Lambda-calculus notation to think in terms of, so the learning curve wasn't evident to them.)
The point I'm getting at, here, is that any programming language syntax can have Lisp-transformation-model semantics. As long as `read` and `eval` are separate functions of your compiler+runtime, and the AST that normally travels between the two can be manipulated by your own code, you have a Lisp.
That's what people mean when they say that "the parentheses don't matter."
My guess is that what people complain about isn't really the parentheses, but rather heavy nesting of Lisp programs compared to other languages. If parentheses were replaced with something else, they'd probably complain about that something else.
Except that most modern lisps don't even nest that deeply anymore. At least, not anymore than every functional language that uses nesting to offer new immutable lexical scopes does.
Seriously, the average nesting depth of a C program is maybe 3-4 (function, conditional, loop, etc), and C programs are simple. More complex languages like Java and C++ will easily have 4-7 levels of nesting on average. Clojure and Arc code are probably right on par with that.
It seems pointless to mandate it, but I don't think it'd really cause a problem for most real-world clojure programs. For one, cyclomatic complexicty measures independent paths, and I don't think that's what most people are complaining about when they say "lisp has too many parenthesis". They're complaining about how the structures expected require a lot of (sometimes arduous-seeming) complexity.
Indeed, I suspect that the cyclomatic complexity of an average lisp function will be less than that of, say, the average Python function. It'd be the same with any functional language; they encourage you to only have one or two conditionals per function.
It took me a long time to get used to this in functional programming, and I got annoyed with how deeply nested my code got. Then I learned that it was just the language telling me to decompose my functions! :-)
It's not a problem at all, there is zero readability cost to all of
those parens. Nobody with any experience coding lisp has any trouble
reading it. Personally, I find lisp code to be considerably easier to
read than other languages that I otherwise prefer.
Fantastic article, though the analogy to the Eiffel tower is a bit weak. It's a good exposition into the argument as to why "code is data," is a relevant and valuable argument. Lisp is a wonderful language and I love those damn parenthesis. :)
Lisp is a remarkable toolkit for creating domain-specific languages with any syntax you happen to need. It amazes me how many people try to use it as an ordinary programming language without modifying it at all, and then give up because they found nothing special about it. I think they're missing the point.
With these reader macros, can the code in the blog example be rewritten as below, so it still directly maps to the Lisp tree-like semantics, but be more readable?
I have to admit that I'm not an expert on reader macros, so I can't say for sure. Your example seems to map some already used characters, so it wouldn't be a pure extension of the reader. I guess you could make a readtable that recognizes that syntax and transforms it to the tree-like semantics. FWIW, I don't find it more readable than the standard notation. Maybe I have become too accustomed to the standard CL-notation.
"too many parenthesis" is simply a flag that someone is speaking only about his initial emotional response, not out of actual use experience or measurement. When you actually count parenthesis in equivalent programs in C (or C-like syntax) and Lisp, they are almost exactly the same. When you include the ;.->*& -stuff, C starts to lose because `foo.bar();´ in C becomes simply `(bar foo)´ in Lisp.
Those who keep going on and on about parentheses in Lisp should try Haskell, which is basically* Lisp, except everything has one argument and is left associative. This simple rule removes a TON of parens. Add in the $, . operators and a bunch of other potential parentheses are eliminated.
*Except also that Haskell is typed and does not include code quoting/eval. But that's what Template Haskell is for :)
Also, you don't need to invent backcronyms for CAR/CDR, they're now called first/rest.
Having said that, I really like the presentation of your blog, nice typography. And after skimming your book[1] in progress, and noting your obvious theoretical bent and taste for rigor, I can only anticipate to read more of your future posts (latch on to something "obscure" like ACL2 and make something fun with it.)
[1] http://symbo1ics.com/blog/?page_id=77
[Edit:
The book has code samples in 4 different languages; LISP (the ancient cap-cased "one"), ML, C, and what looks like Pascal. If you want to learn about the axiomatic specification of computer programs, specially for "structured" programming, then look into the works of Gries and others, specially in the silver "Texts and Monographs In Computer Science" books (the entire series is a feast of delight that should be devoured, and washed down with heirloom, stolen wine):
The Science of Programming, Gries.
The Design of Well-Structured and Correct Programs, Alagic and Arbib.
The selection Programming Methodology edited by Gries has various approaches to the structured method, with contributions from Dijkstra, Hoare, Wirth, Reynolds and other rock-stars of axiomatic semantics and verification.]