Hacker News new | past | comments | ask | show | jobs | submit login
Lisp has too many parentheses... (symbo1ics.com)
66 points by zephyrfalcon on Nov 9, 2010 | hide | past | favorite | 77 comments



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.)

[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.]


Exactly what I was thinking, though I do still enjoy seeing CAR and CDR. But I'm the kind of guy who likes steampunk, and it's in the same vein.

I, too, am looking forward to more posts; it's worth checking out the posts that are up already. Definitely my kind of thing (see my http://copperthoughts.com/p/set-theory-and-lisp/).

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.


The bigger problem is that CAR and CDR actually mean something without the silly anatomy analogies.


Actually, I like "anterior" and "dorsal" better than assembly instructions from the 1950s.


The first thing I noticed too, then I stopped reading :(


So when you call them first and rest, how do you destructure lists of lists?

Actually, now that I think about it, "fire" is much cooler sounding than "cadr". But not as cool sounding as cadadr.


For me, the following is a lot more readable than cadadr:

  (def coll [[1 2 3]
             [4 5 6]
             [7 8 9]])
  (second (second coll)) ; => 5
And often when I'm digging deep inside a nested data structure, I don't need just one piece of data, so destructuring comes in handy:

  (let [[[top-left]
         [_ middle] 
         [_ _ bottom-right]] coll]
    [top-left middle bottom-right]) ; => [1 5 9]


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.


or the "->" ("threading") macro, a recursive solution, or a lib like

http://groups.google.com/group/clojure/browse_frm/thread/11a...


destructuring-bind ;)


I've posted this here before, I'll post it again:

http://img264.imageshack.us/img264/1397/lispnd7.png

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.

BTW, while Halstead metric predict various things about imperative languages like Algol/PL/1/C/C++/Java quite well, it fails when applied to Haskell: http://www.cs.stir.ac.uk/~kjt/techreps/pdf/TR141.pdf

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.


There's an emacs mode for that. (http://www.emacswiki.org/emacs/UnParenMode)

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.


> comment box that happens to eat whitespace

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?"


Paul Graham says:

> 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.

http://www.paulgraham.com/popular.html


By requiring parenthesis, indentation becomes so much simpler, the programmer doesn't even have to do it. It's done automagically.


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.


"automagically", "I just hit tab"

You and Understanding are not exactly on speaking terms, are you?


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?


I've fought Python's "semantic" indentation at least as much as I've fought ; : => , ( ) { } [ ] _ ' " $ < > | \ \\ \\\\ / ... et al.


Perhaps Haskell can be an inspiration?


A cheap hack many have used is to customize their emacs high-lighting so the parens are shown only a shade away from the background color.


http://srfi.schemers.org/srfi-49/srfi-49.html

I think it's a terrible idea, but there you go.


"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".)


    "Dorsal" means "top", like where the dorsal fin on a fish is.

http://www.google.com/search?sourceid=chrome&ie=UTF-8...

e.g. "of, pertaining to, or situated at the back, or dorsum."

Seems fish are the oddball, in a way. Their top is basically their back.


There's an incongruity between animal and human anatomy. In humans, dorsal does indeed mean back, not top.

Wikipedia has a wall of text by way of explanation:

http://en.wikipedia.org/wiki/Anatomical_terms_of_location#Wh...


Except, as far as humans are concerned, "dorsal" and "posterior" are synonymous.


dictionary.com seems to think you're kind of both right[1].

[1] http://dictionary.reference.com/browse/dorsal


Nice article. Though a bit smug; Forth (or even Scheme) have a much cleaner syntax than the Lisp advertised here.


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).


This argument/response comes up every time....

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.

Here's a DSL I'm working on for CouchDB:

  (defmapping post
    :pre-commit timestamp
    :fields     {:author-id :string
                 :title     :string
                 :created   :date-time
                 :modified  :date-time
                 :body      :string
                 :tags      [:string]
                 :meta      {:copyright :string
                             :href      :string}})
I wish my work in other languages had this kind of structural clarity all the time!

In constrast my favorite Python lib for CouchDB work looks like this:

  creators = ListField(DictField(Mapping.build(
                         name    = DictField(Mapping.build(
                                     name_authority    = TextField(),
                                     name_authority_id = IntegerField(),
                                     display_string    = TextField()
                                   )),
                         user_id = IntegerField(),
                         roles   = ListField(TextField()),
                         attrs   = ListField(TextField()),
                         xts     = ListField(TextField()),
                       )))
Just look at all those parens!


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.


  creators = [{"name"   :{"name_authority"    :TextField,
                          "name_authority_id" :IntegerField,
                          "display_string"    :TextField},
              "user_id" :IntegerField,
              "roles"   :[TextField],
              "attrs"   :[TextField],
              "xts"     :[TextField]}]
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.


Use single quotes; less noise.


who writes code like that?

    creators = [
        {
            "name": {
                "name_authority": TextField,
                "name_authority_id": IntegerField,
                "display_string": TextField
            },
            "user_id" :IntegerField,
            "roles": [TextField],
            "attrs": [TextField],
            "xts": [TextField]
        }
    ]

anyway


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."


This doesn't address the real point -- you can't read it well.

By "you", don't you mean you?


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.


What happens when a VP of Engineering decides that Cyclomatic complexity will be capped at 10:

http://stackoverflow.com/questions/105852/conditional-loggin...


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.


Indeed.

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.


And machine code printed in binary is all 1's & 0's. What could be more elegant than that?


Lisp.


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. :)


@mahmud I don't have to invent backronyms for urmom.


Money quote for the non-lisper:

> For simplicity, let’s use the notation

Yes, let's! Except in lisp, you can't. ;)

(Yes, feeling snarky.)


Except you can, just use reader macros.


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?

  defun diff(expr, x){
    if(expr == x) 1
    else if(car(expr) == 'plus') ['plus', diff(cadr(expr), x), caddr(expr), x]
    else if(car(expr) == 'times')[
      'plus',
      ['times', cadr(expr), diff(caddr(expr), x)],
      ['times', diff(cadr(expr), x), caddr(expr)]
    ]else 0
  }


I'm sure it's possible; lisp is very flexible.

But would your example code still be considered lisp?


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 :)


Except that I find myself adding tons of parens to my haskell to be able to read it. Lisp may have spoiled me.


I always liked the way Larry Wall put it: "Lisp has all the visual appeal of oatmeal with fingernail clippings mixed in."

http://groups.google.com/group/comp.lang.lisp/msg/7700fb02a2...


then he went on and desi^h^h^h^h ... crea^h^h^h^h ... hacked Perl...




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

Search: