This is a read-only archive!

Lisp Syntax Doesn't Suck

I spend a lot of time talking about what I don't like about various languages, but I never talk about what I do like. And I do like a lot, or I wouldn't spend so much time programming and talking about programming.

So here goes. I like the syntax of Lisp. I like the prefix notation and the parentheses.

Common Complaints

A common criticism of Lisp from non-Lispers is that the syntax is ugly and weird. The parentheses are impossible to keep balanced. It ends up looking like "oatmeal with fingernail clippings mixed in".

Also, prefix notation is horrible. 1 + 2 is far superior to (+ 1 2). Infix notation is how everyone learns things and how all the other languages do it. There are countless numbers of people (example) who have proposed to "fix" this, to give Lisp some kind of infix notation. The topic inevitably comes up on Lisp mailing lists and forums.

Partly this is subjective opinion and can't be argued with. I can't say that Lispy parens shouldn't be ugly for people, any more than I can say that someone is wrong to think that peanut butter is gross even though I like the taste of it. But in another sense, does it matter that it's painful? Does it need to be changed? Should the weird syntax stop you from learning Lisp?

Prefix Notation: Not Intuitive?

There is no "intuitive" when it comes to programming. There's only what we're used to and what we aren't.

What does = mean in a programming language? Most people from a C-ish background will immediately say assignment. x = 1 means "give the variable/memory location called X the value 1".

For non-programmers, = is actually an equality test or a statement of truth. 2 + 2 = 4; this is either a true or false statement. There is no "assignment". The notion of assignment statements is an odd bit of programming-specific jargon. In most programming languages we've learned instead that == is an equality test. Of course some have := for assignment and = for equality tests. But = and == seems to be more common. Some languages even have ===. Or x.equals(y). Even less like what we're used to. (Don't get started on such magic as +=.)

Most of us have no problem with these, after a while. But few of us were programmers before we learned basic math. How many of us remember the point in time when we had to re-adjust our thinking that = means something other than what we've always learned it to mean? I actually do remember learning this, over a decade ago. This kind of un-learning is painful and confusing, there's no question.

But it's also necessary, because these kinds of conventions are arbitrary and vary between fields of study (and between programming languages). And there are only so many symbols and words available to use, so we re-use them. None of the meanings for = is "right" or more "intuitive" than the other. = has no inherent meaning. It means whatever we want it to mean. Programming is chock-full of things like this that makes no sense until you memorize the meaning of them.

Consider a recent article that got a lot of discussion, about why all programmers should program in English. How much less intuitive can you get, for a native speaker of another language to program using words in English? Yet they manage. (Have you ever learned to read sheet music? Most of the terms are in Italian. I don't speak a word of Italian, yet I managed.)

The point is that it's very painful to un-learn things that seem intuitive, and to re-adjust your thinking, but it's also very possible. We've all done it before to get to where we are. We can all do it again if we need to.

Prefix notation is unfamiliar and painful for many people. When I first started learning Lisp, the prefix notation was awfully hard to read without effort, even harder to write. I would constantly trip up. This is a real distraction when you're trying to write code and need to concentrate. But it only took me maybe a week of constant use to ingrain prefix notation to the point where it didn't look completely alien any longer.

At this point prefix notation reads to me as easily as infix notation. I breeze right through Lisp code without a pause. In Clojure, you can write calls to Java methods in Java order like (. object method arg arg arg) or you can use a Lispy order like (.method object arg arg arg); I find myself invariably using the Lispy way, as does most of the community, even though the more traditional notation is available.

You can get used to it if you put in a minimal amount of effort. It's not that hard.

Benefits of Prefix Notation

Why bother using prefix notation if infix and prefix are equally good (or bad)? For one thing, prefix notation lets you have variable-length parameter lists for things that are binary operations in other languages. In an infix language you must say 1 + 2 + 3 + 4 + 5. In a prefix language you can get away with (+ 1 2 3 4 5). This is a good thing; it's more concise and it makes sense.

Most languages stop at offering binary operators because that's as good as you get when you have infix operators. There's a ternary operator x?y:z but it's an exception. In Lisp it's rare to find a function artificially limited to two arguments. Functions tend to take as many arguments as you want to throw at them (if it makes sense for that function).

Prefix notation is consistent. It's always (function arg arg arg). The function comes first, everything else is an argument. Other languages are not consistent. Which is it, foo(bar, baz), or bar.foo(baz)? There are even oddities in some languages where to overload a + operator, you write the function definition prefix, operator+(obj1, obj2), but to call that same function you do it infix, obj1 + obj2.

The consistency of Lisp's prefix notation opens up new possibilities for Lispy languages (at least, Lisp-1 languages). If the language knows the first thing in a list is a function, you can put any odd thing you want in there and the compiler will know to call it as a function. A lambda expression (anonymous function)? Sure. A variable whose value is a function? Why not? And if you put a variable whose value is a function in some place other than at the start of a list, the language knows you mean to pass that function as an argument, not call it. Other languages are far more rigid, and must resort to special cases (like Ruby's rather ugly block-passing syntax, or explicit .call or .send).

Consistency is good. It's one less thing you have to think about, it's one less thing the compiler has to deal with. Consistent things can be understood and abstracted away more easily than special cases. The syntax of most languages largely consists of special cases.

Parens: Use Your Editor

The second major supposed problem with Lisp syntax is the parens. How do you keep those things balanced? How do you read that mess?

Programming languages are partly for human beings and partly for computers. Programming in binary machine code would be impossible to read for a human. Programming in English prose would be impossible to parse and turn into a program for a computer. So we meet the computer halfway. The only question is where to draw the line.

The line is usually closer to the computer than to the human, for any sufficiently powerful language. There are very few programing languages where we don't have to manually line things up or match delimiters or carefully keep track of punctuation (or syntactic whitespace, or equivalent).

For example, any language with strings already makes you pay careful attention to quotation marks. And if you embed a quotation mark in a quote-delimited string, you have to worry about escaping. And yet we manage. In fact I think that shell-escaping strings is a much hairier problem than balancing a lot of parens, but we still manage.

This is sadly a problem we must deal with as programmers trying to talk to computers. And we deal with it partly by having tools to help us. Modern text editors do parenthesis matching for you. If you put the cursor on a paren, it highlights the match. In Vim you can bounce on the % key to jump the cursor between matching parens. Many editors go one step further and insert the closing paren whenever you insert an opening one. Emacs of course goes one step further still and gives you ParEdit. Some editors will even color your parens like a rainbow, if that floats your boat. Keeping parens matched isn't so hard when you have a good editor.

And Lisp isn't all about the parens. There are also generally-accepted rules about indentation. No one writes this:

(defn foo [x y] (if (= (+ x 5) y) (f1 (+ 3 x)) (f2 y)))

That is hard to read, sure. Instead we write this:

(defn foo [x y]
  (if (= (+ x 5) y)
    (f1 (+ 3 x))
    (f2 y)))

This is no more difficult to scan visually than any other language, once you're used to seeing it. And all good text editors will indent your code strangely if you forget to close a paren. It will be immediately obvious.

A common sentiment in various Lisp communities is that Lispers don't even see the parens; they only see the indentation. I wouldn't go that far, but I would say that the indentation makes Lisp code easily bearable. As bearable as a bunch of gibberish words and punctuation characters can ever be for a human mind.

When I was first learning Lisp I did have some pain with the parens. For about a week. After learning the features of Vim and Emacs that help with paren-matching, that pain went away. Today I find it easier to work with and manipulate paren-laden code than I do to work with other languages.

Benefits of the Parens

Why bother with all the parens if there's no benefit? One benefit is lack of precedence rules. Lisp syntax has no "order of operations". Quick, what does 1 + 2 * 3 / 4 - 5 mean? Not so hard, but it takes you a second or two of thinking. In Lisp there is no question: (- (+ 1 (/ (* 2 3) 4)) 5). It's always explicit. (It'd look better properly indented.)

This is one less little thing you need to keep in short-term memory. One less source of subtle errors. One less thing to memorize and pay attention to. In languages with precedence rules, you usually end up liberally splattering parens all over your code anyways, to disambiguate it. Lisp just makes you do it consistently.

As I hinted, code with lots of parens is easy for an editor to understand. This make it easier to manipulate, which makes it faster to write and edit. Editors can take advantage, and give you powerful commands to play with your paren-delimited code.

In Vim you can do a ya( to copy an s-exp. Vim will properly match the parens of course, skipping nested ones. Similarly in Emacs you can do C-M-k to kill an s-exp. How do you copy one "expression" in Ruby? An expression may be one line, or five lines, or fifty lines, or half a line if you separate two statements with a semi-colon. How do you select a code block? It might be delimited by do/end, or curly braces, or def/end, or who knows. There are plugins like matchit and huge syntax-parsing scripts to help editors understand Ruby code and do these things, but it's not as clean as Lisp code. Not as easy to implement and not as fool-proof that it'll work in all corner cases.

ParEdit in Emacs gives you other commands, to split s-exps, to join them together, to move the cursor between them easily, to wrap and unwrap expressions in new parens. This is all you need to manipulate any part of Lisp code. It opens up possibilities that are difficult or impossible to do correctly in a language with less regular syntax.

Of course this consistency is also partly why Lisps can have such nice macro systems to make programmatic code-generation so easy. It's far easier to construct Lisp code as a bunch of nested lists, than to concatenate together strings in a proper way for your non-Lisp language of choice to parse.

Conclusion

Yeah Lisp syntax isn't intuitive. But nothing really is. You can get used to it. It's that not hard. It has benefits.

Sometimes it's worth learning things that aren't intuitive. You limit yourself and miss out on some good things if you stick with what you already know, or what feels safe and sound.

April 07, 2009 @ 9:03 PM PDT
Cateogory: Programming
Tags: Lisp, Rant

45 Comments

rzezeski
Quoth rzezeski on April 07, 2009 @ 11:35 PM PDT

+1

Another nice feature is that Lisp is applied Lambda Calculus, and Lambda Calculus (to my understand) started as an investigation to explain all of mathematics with the least number of idioms (the smallest foundation). This is probably why Rich Hickey can explain Clojure "syntax" in one page (he does so in one of the screencasts). You don't need to remember esoteric facts from a 500 page book to be able to visually parse Lisp code.

Also, if you can read one Lisp, it isn't too hard to read another. Can the same be said for the Algol family? I mean how easy is it to go from Java to Ruby to C++ to C# to Pascal?

Lisp is not a panacea, but man it's cool as hell.

Dave Doyle
Quoth Dave Doyle on April 07, 2009 @ 11:43 PM PDT

I don't know Lisp. I have seen it of course... and it does look strange to me. That being said:

There is no "intuitive" when it comes to programming. There's only what we're used to and what we aren't.

Thank you, thank you, thank you. That is the single most important thing about programming everyone should keep in mind. Every time I hear the world "intuitive" applied to programming I want to scream.

A fellow recently did a presentation at my local PerlMongers group on "Lispy Perl" and setup a parser for using s-expressions directly in Perl. Definitely worth another look.

James
Quoth James on April 08, 2009 @ 1:33 AM PDT

This is an interesting topic. I'd like to make a suggestion on how to improve on Lisp's parentheses: add the ability to use different kinds of parentheses/braces/brackets to help readers parse expressions, just as in mathematical notation: for example, {+ (+ [* 3 4] [* 5 6]) 2} instead of (+ (+ (* 3 4) (* 5 6)) 2). Even better, a non-ASCII editor/IDE would allow the use of multiple parenthesis/brace/bracket sizes as well (again, this is commonly done in math to further enhance readability).

Bob
Quoth Bob on April 08, 2009 @ 2:41 AM PDT

James, many Scheme implementations allow for mixing of [] and ()

A reader macro to accomplish it would also be fairly trivial, so I imagine there is a CL library somewhere for that if you want.

John Haugeland
Quoth John Haugeland on April 08, 2009 @ 3:19 AM PDT

"and Lambda Calculus (to my understand) started as an investigation to explain all of mathematics with the least number of idioms (the smallest foundation)."

Can't imagine why you believe this. Most people are aware of things like Whitehead+Russel's Principia Mathematica, or Peano's work, though Al Q'arizhmi put in a pretty respectable effort to that end (as far as someone could have gotten with that level of math) nearly a thousand years earlier. For that matter, Pythagoras wrote a lot about the power of reductionism and the importance of finding what he called "the atoms of mathematics."

Hell, neither Lisp nor Church's Lambda (which predates lisp by like ten years) even brought core representation reductionism to computer science, let alone math; that's almost certainly Aitken's Autocoder, though there are good arguments for the Turing machine, Brooker Autocode, Eniac C-10, BALGOL, Runcible 2, Fortran II or Midac ITP, all of which predate LISP by years and years.

And, of course, you're assuming - quite falsely - that Lisp had the lambda from day one. The language presented in 1958 is quite different than what you know today.

sMAshdot
Quoth sMAshdot on April 08, 2009 @ 3:44 AM PDT

how ironic you forgot a paren in (- (+ 1 (/ (* 2 3) 4) 5) ;-)

Justin
Quoth Justin on April 08, 2009 @ 3:56 AM PDT

"how ironic you forgot a paren in (- (+ 1 (/ (* 2 3) 4) 5) ;-)"

Just goes to show how paren matching in a decent editor makes the age old argument somewhat irrelevant. Of course without matching it would be an unbalanced nightmare.

Brian
Quoth Brian on April 08, 2009 @ 3:59 AM PDT

@sMAshdot: Heh, yeah a browser textarea isn't the best place for writing Lisp code.

Binny V A
Quoth Binny V A on April 08, 2009 @ 4:06 AM PDT

I don't mind postfix - or even the parans. My trouble with lisp is the trouble finding libraries. Does Lisp have something like Perl's CPAN?

WILL
Quoth WILL on April 08, 2009 @ 4:15 AM PDT

This might be more succinct: (+ 1 2 3 4), but once you get into mixing operators, things get complex, i.e., your own example: (- (+ 1 (/ (* 2 3) 4) 5)). Don't even say that's easier to read than infix notation.

Also - adding up multiple numbers like this is rare in programming to begin with. Most likely you're going to be looping through a large list of numbers.

Brian
Quoth Brian on April 08, 2009 @ 4:29 AM PDT

@WILL: My example is easy for me to read. Easier than infix? Probably not, but only because I'm more used to infix, as we all are. I don't doubt that my example may be hard for others to read, but you can get used to anything, that's my point.

I read my example inside-out, starting in the middle and working outward. Infix notation pretends like you can read it left-to-right, but then precedence kicks in and you end up scanning back and forth anyways. Same mess, different dressing.

In Lisp I would do (apply + some-list-of-numbers) or use reduce. An explicit loop is usually overkill.

@Binny V A: Not really. But Clojure can use Java libraries, that's one reason I like it.

rzezeski
Quoth rzezeski on April 08, 2009 @ 4:54 AM PDT

@John: You certainly know more mathematics than I, but you missed my point. The "syntax" of Lisp is based on a very small set of atomics from which it can then begin bootstrapping itself. Thus, it takes very little effort to learn the syntactic rules, at least compared to other languages such as Java or C++. Learning the language OTOH, well that's a whole 'nother story.

Personally, the closest Algol based language I've found that compares in conciseness (ie, conciseness of syntax rules) is C. Once again, the syntax doesn't take long to master, but mastering the language takes a life time (or 10 years if you're Peter Norvig).

Rachel Blum
Quoth Rachel Blum on April 08, 2009 @ 4:55 AM PDT

I'd argue that people complaining about lisp syntax really mean "This thing is TERSE!"

And it sure is. Most non-lispy languages achieve at least a modicum of readability for your average english-speaking person. Lisp does not. Instead, it is very readable for the average person that manages to think like a machine. (I don't mean that as an indictment - it's a feature, but one that costs it audience)

In a way, Lisp is to functional languages as assembly is to high level languages. (No, not in terms of features. Just the way it feels when programming it)

That seems to be what all the Lisp noise is about. I get exactly the same noise when I demand that programmers need to be able to read assembly fluently. (It's not intuitive, it's outdated, you can never achieve anything of size in it, etc...)

So arguing if lisp syntax is "intuitive" or not is ultimately a straw man. (But it sure gets the reddit juice flowing ;)

aartist
Quoth aartist on April 08, 2009 @ 5:55 AM PDT

I like lisp but for one thing. ForSomething like this: (- (+ 1 (/ (* 2 3) 4) 5) 6) you have to start reading inside first. ie.. until you get (* 2 3) it doesn't make sense to read outside things. May be I am used read that way, but that is reverse from most things I see in programming or even in non-programming world.

aartist
Quoth aartist on April 08, 2009 @ 6:03 AM PDT

I would welcome any readability translator for lisp.

For example: (- (+ 1 (/ (* 2 3) 4) 5) 6) can be represented as

(* 2 3)

(/ X 4)

(+ X 1 5 )

(- X 6)

For the sake of readability. (X is previous result)

Unlike Perl I cannot digest all in one go. I need pieces. Is it the matter of practice only?

Rachel Baum mentioned: Instead, it is very readable for the average person that manages to think like a machine. (I don't mean that as an indictment - it's a feature, but one that costs it audience)

Above won't cost the audience.

Marcus Garvey
Quoth Marcus Garvey on April 08, 2009 @ 6:24 AM PDT

Interesting read; I do have one point to make: for most of the world, '=' is more than just equality (although it's an easy argument to make.) It can also about assignment, although you can make the mathematical point that equality and assignment are the same thing on some level. == is more of a function than a statement. I think you may be cherry picking facts to support your thesis.

Anyways, I'm not convinced. I'm used to algebra, calculus and all that. Lisp's syntax is nothing like it. When people speak of intuitive languages, I think that they are talking about the similarity to high-school Alg. 1A stuff (what's been beaten into our heads.) Lisp certainly doesn't fit that bill.

mark
Quoth mark on April 08, 2009 @ 7:08 AM PDT

Two problems:

  • Prefix notation is not how our world operates.

1 + 2 will be how our world works. Doing

(+ 1 2) is trying to change this, and will never work.

  • In Ruby parens are optional most of the time. In Lisp they are mandatory. When you critisize ruby, at least have the decency and include that.

Also, = can have different meanings depending on the situation in our real world or in maths. Lisp never became the de facto language for Math guys, so I am sorry to say but I am VERY sceptical about your conclusions.

a random hack
Quoth a random hack on April 08, 2009 @ 7:20 AM PDT

You forgot the most salient feature of s-expression syntax: uniformity, which makes it natural to write program transformers [aka macros].

In fact, I will go as far as arguing that it is impossible to have proper macros without s-expressions; macros are ast manipulators, and s-expressions are the natural representation of an ast.

Rachel Blum
Quoth Rachel Blum on April 08, 2009 @ 7:51 AM PDT

In Ruby parens are optional most of the time. In Lisp they are mandatory. When you critisize ruby, at least have the decency and include that

He did Ruby a favor by not mentioning that. Any syntax that does things "most of the time" is inevitably harder to write. All the Ruby code I write uses parens all the time, because I don't want to expand mental capacity on figuring out if I can possibly leave them out this time.

Steve
Quoth Steve on April 08, 2009 @ 8:37 AM PDT

I have programmed in Lisp (well, specifically Scheme) and I hated it with a passion. I completely disagree that indending Lisp code makes it as readable as any other language - the sheer number of parens makes it much harder to read than, say, python. I partly agree that a combination of prefix notation and parens lead to less ambiguous statements, but I also think that there are many instances in Lisp where there are simply too many parentheses.

And while it's certainly possible to get used to using different operators for different purposes (= or := for assignment, as you say) I don't think it's anywhere near as simple to change to using prefix notation from infix for the simple reason that we've been doing maths a particular way for far longer than we've been programming and it's more ingrained in us to do it that way.

Vincent Foley
Quoth Vincent Foley on April 08, 2009 @ 9:27 AM PDT

Why is it that for math operators, people who generally dislike Lisp can't fathom using prefix notation, but have no problems doing so for virtually every other operation? String concatenation is done with str[nl]cat() in C. Do you hear C programmers falling all over themselves, crying in their sleep at night about how abominable that is when Java and Python use + instead? Are PHP programmers unable to cope with the fact that they need to use *gulp* a function to test if an element is part of an array instead of using the much simpler "foo in bar" form of Python?

The fact is, if anyone used Lisp for more than an hour, they'd realize that the prefix syntax is a total non-issue. The most common math operations in a program are adding one and subtracting one.

Here, humor me: without using a language reference, parenthesize the following expression as it would be interpreted:

1 & 2 + 3 ^ 4 || 5 * 6 | 7 - 8 && 9
rzezeski
Quoth rzezeski on April 08, 2009 @ 10:06 AM PDT

@Vincent: Quick! Get your flame suit on! :)

Well, I think all these comments have proved one of Brian's points; much of this is subjective, and it's really about acquiring a taste for something.

Forgive my poor analogy, but it's kind of like coffee. No kid in their right mind likes coffee, but over time many people "acquire" a taste for it and it becomes a vital part of their day. They can't imagine life without it!

Fact is, PLs are just like religion or politics. Just about everyone has an opinion, and it just so happens to be the objectively correct one. This will be an eternal debate...until The Matrix errors and a SLIME debugger is staring us all in the face. :)

BTW, I hate coffee, and everything I say is pure rubbish.

Rachel Blum
Quoth Rachel Blum on April 08, 2009 @ 10:59 AM PDT

@Vincent: Only if you tell me which language it is ;)

@rzezeski: I swear, if The Matrix needs to be debugged using Emacs, I'll take the red pill. And the blue pill. And all other pills I can get my hands on ;) (And vim is only marginally better. Time has kind of moved on since the early 90's ;)

SJS
Quoth SJS on April 08, 2009 @ 12:35 PM PDT

It takes me a couple of hours of working with a lispy-language before I'm working "smoothly" in it. If I'm using it every day, that eventually gets down to about half-an-hour, at least until I take a couple of days off, and then I'm back to square one. I'm not entirely sure why this is, but it certainly puts me off using a lispy language for anything but toy problems.

One of the problems I think people have with prefix notation is the use of symbols and nesting. A programmer may have no problem with ADD R1, R2 SUB R1, R3 MOV R1, #LOC but reject outright

(set loc (- (+ r1 r2 ) r3 ) )

partially because the symbols mean the programmer has to see the symbol, give it a name, look for the innermost expression, and then work their way back out, translating back from the name to the symbol to next look for. At least that's a guess.

One of my problems isn't really a problem with the syntax, but with how most programmers write their code. The example given above is a good one:

(defn foo [x y] (if (= (+ x 5) y) (f1 (+ 3 x)) (f2 y)))

When I read that code, I wonder where the end of the if and the defn are. There's no visual clue, the program just keeps crawling over to the right margin, and I get lost.

(This is also why I hate trying to read Python - it doesn't make any sense to me, I lose track of all scoping and block structure. I have the same problem with the GNU style of brace indenting for C. It's just the way some people are wired, I think.)

I can reformat the above code to help, like so: (defn foo [x y] (if (= (+ x 5) y) (f1 (+ 3 x)) (f2 y) ) )

...but that's not the way the tools want to format the code, nor does the bulk of the community want to look at code that way: they don't mind thirty levels of indentation and a whole slew of close-parens. Fighting the community is a good way to be miserable, as is putting up with idiotic (to you) conventions.

"You'll get used to it" is a lousy defense for a misfeature.

What actually surprises me is that LISP isn't the target for every new and experimental language. Consider, you have a program that basically runs an AST. The first thing you do with a new language is to write a tokenizer and parser to generate an AST. LISP should've been the JVM of its time -- every new experimental language should have simply been a thin layer to generate the appropriate AST, which could then run directly on whatever lisp interpreter was available.

The problem was, I think, that LISPers don't WANT other languages. They want just one. Lisp is so powerful and elegant and clean and unencumbered by needless syntax, why would anyone WANT to use any other language?

And that's a problem too -- the constraints and limitations of a language may keep you from doing some things easily, but it guides you towards a reasonable solution. That's a useful feature for a language to have, assuming you're open to using more than one language.

David
Quoth David on April 08, 2009 @ 2:49 PM PDT

This is idiotic. It just drives home the point that Lisp people are stubborn and arrogant.

Anonymous Cow
Quoth Anonymous Cow on April 08, 2009 @ 5:27 PM PDT

I use Lisp very often, and I don't think it should be the only language in the world. If it could be, there'd be no need for GUIs -- people would just interface with a Lisp repl (the command line thing).

If you need support for that common class of arithmetic expressions -- +*-/^ -- you can use an infix library. The Lisp "compiler" is extendable by users, not just language implementors, so you can do such things that normally the implementor would do...

I do agree that vanilla Lisp doesn't provide the most readable notation for long arithmetic expressions, but Lisp is general-purpose. To use a maybe questionable analogy, to be human means you're not going to swim as well as a shark or fly like a bird. Also, an animal that swims well won't have the features to fly well. These are tradeoffs.

(I don't mean anything offensive by that analogy; and anyway, many gaze outside the window and wish to fly like a bird.)

For me, I'm happy to use Lisp to mix HTML easily into my code. And with tools like Paredit, the parens give me a "grip" on code. I've been using PHP recentlly, the great web language, and its so maddening trying to deal with figuring out what goes with which . I use Lisp to help me deal with PHP as much as feasible.

Tayssir
Quoth Tayssir on April 08, 2009 @ 5:28 PM PDT

Sorry -- that last post was by me; forgot to sign my name to it.

Fred
Quoth Fred on April 09, 2009 @ 7:24 AM PDT

As you see in these comments, the Lisp haters are at least as stubborn as they accuse us Lisp Lovers to be. Either they don't understand your arguments or they refuse to do so. But that's not your fault. I also don't know what to do about this.

One minor point about arithmetic expressions in Lisp is that the function name 1- in Common Lisp was chosen badly, Scheme did it better with -1+.

LISt Possessor
Quoth LISt Possessor on April 09, 2009 @ 9:57 AM PDT

Having used postfix notation on an HP calculator back in the seventies, prefix notation was not a significant hurdle for me in learning LISP. It was the time it took to express one-off programs in LISP style that caused me to abandon the language.

Brian
Quoth Brian on April 09, 2009 @ 10:20 AM PDT

@Fred: I think most people didn't even read what I wrote. The hit-and-run readers from Reddit mostly. They saw "Lisp" and "syntax" and "parens" and starting having a nose bleed. Such is life.

Tavs
Quoth Tavs on April 10, 2009 @ 3:22 AM PDT

@Binny: check Cliki for gpl Common Lisp libraries.

Otherwise, use Java ones via Clojure.

enjoy!

Josh
Quoth Josh on April 13, 2009 @ 12:54 AM PDT

Mark said:

  • Prefix notation is not how our world operates.

1 + 2 will be how our world works. Doing

(+ 1 2) is trying to change this, and will never work.

That depends on how you say it. If you say, "One plus two," then infix makes more "sense". But if you say, "The sum of one and two," then prefix makes more "sense". I must say that the more mathematicians I spend time with, the more I realize the second is actually more precise (and more normal within that subculture).

Consider one of the bigger expressions:

(- (+ 1 (/ (* 2 3) 4)) 5)

vs.

1 + 2 * 3 / 4 - 5

"One plus two times three over four minus five"?

Or, "The difference of the sum of one and the ratio of the product of two and three over four and five."

I submit that neither are sufficient to understand in English. Why would you care, then, how we would render it in a natural language when we're talking about how to precisely denote it in a programming language?

You have two choices -- explicit control by parentheses or prior knowledge of a set of rules controlling the order of operations. Is one better than the other? Arguably, each has advantages.

Matthias
Quoth Matthias on August 02, 2009 @ 12:44 AM PDT

I always hated operator precedence at school. In the fith grade we spent weeks on learning it and after a half year most kids had learned it. So arguing infix notation is natural is simply wrong. It even becomes harder with terms like: a sin 30 = 3cd

I think prefix notation and RPN are superior to this.

However, I have some doubts about the parenthesis syntax of LISP. For an unexperienced persons it is probably easier to read Python code, because indention is easier to parse for them. This may be just a matter of training, but I'm not sure.

But the LISP syntax has advantages as well. Consider the following Dylan expression:

let x = if (condition)
          foo();
        else
           bar();
        end;

or:

let x = if (condition) foo(); else bar(); end;

The LISP-like equivalent (Dylan has an ALGOL-like syntax for Common Lisp) is clearer and looks nicer:

(let x (if (condition) (foo ()) (bar())))

You could also nest a lambda function which would further complicate the Dylan code.

Most programmers solve this problem by breaking the expression up and inventing meaningless names for temporary variables. In LISP you can easily write such nested expressions. I'm not aware of any other language which lets you do that.

Tchalvak
Quoth Tchalvak on August 10, 2009 @ 6:50 AM PDT

Hmmm, I think one major thing that I don't like is the lack of comment mind space.

I've noticed that with clojure, people just don't comment their code well a lot of the time. Which makes it harder for a newb like me to get into the language. I wonder how much of that comes from the fact that since everything often fits into a single ?statement?, any code commenting would be comments that break apart a statement.

e.g.

;; does some math

(/ (+ (/ (* 55 44) 33) 22) 11 10 9 8 7 6)

Only imagine it was much longer... if it were commented at it's most granular, would become something like

;; does some math

(/ (+ (/ (* 55 44)

33) ;; divide by 33

22) ;; plus 22 

11 10 9 8 7 6) ;; divide in turn by each of these

And I think that programmers are even less willing to comment in the middle of their code when it breaks up a continuous statement like that than in the middle of C code, where white space in the middle of everything is so much easier to come by.

Tchalvak
Quoth Tchalvak on August 10, 2009 @ 6:55 AM PDT

Whoops, right, should have read the syntax help at the bottom, but I guess it was too far down to be that visible.

Philip Brocoum
Quoth Philip Brocoum on March 20, 2010 @ 3:25 AM PDT

"Ruby Syntax VS Lisp Syntax"

Despite the obvious technical/theoretical advantage of Lisp’s syntax, I am still going to claim that Ruby’s syntax is superior. The bottom line is that readability trumps almost everything else. Let’s also not forget that mathematicians themselves, arguably the smartest group of people on Earth, chose a syntax that’s easier to read (the “regular” infix syntax that we have now) over a syntax that’s 100% ambiguity-free (Lisp’s syntax).

Boyd
Quoth Boyd on June 05, 2010 @ 5:29 PM PDT

The infix isn't really the problem with Lisp. Actually for programming I prefer infix to the mathematical notation, because the latter has so many rules you have to keep in mind, that it's difficult to figure out what's really going on.

I think the main problem with lisp syntax is that the function is in the same space as it's parameters. Not to mention that the parameters are difficult to distinguish without somekind of delimiter.

so instead of:

(defn foo [x y] (if (= (+ x 5) y) (f1 (+ 3 x)) (f2 y)))

you'd get:

defn(foo, [x, y], if(=(+(x,5), y), f1(+(3,x)), f2(y)))

Now this makes a little bit more sense to me. Yet the lisp basics still remain intact.

Another difficulty I have with lisp, is not so much the syntax as the naming conventions. defn, let? How about something that makes sense? maybe function, var. Anything that means something would be nice.

There are other ways to improve readability, but it seems the lisp community doesn't care about that at all. That's what's put me off lisp so far.

Anonymous Cow
Quoth Anonymous Cow on June 08, 2010 @ 7:32 AM PDT

Josh:

You have two choices -- explicit control by parentheses or prior knowledge of a set of rules controlling the order of operations.

I disagree with you there. Using the infix notation doesn't mean you can't use parantheses. Nothing stops me from writing:

1 + (2 * 3) / 4 - 5

or even:

1 + ((2 * 3) / 4) - 5

That's the biggest difference. In one case, you can use parantheses whenever you feel something isn't readable, in the other you have to, no matter what. I personally like to have a choice, and the fact that I can copy my equations directly into the computer also helps.

TeMPOraL
Quoth TeMPOraL on June 08, 2010 @ 8:51 AM PDT

I think that identation, and general Lisp formatting rules (known as pretty-printing), is essencial to readibility of Lisp code. Let's compare an difficult to read one-liner:

(sqrt (reduce #'+ (map 'vector (lambda (x y) (square (- x y))) vec1 vec2))))

With a properly pretty-printed code:

(defun distance-between-vectors (vec1 vec2)
  (sqrt (reduce #'+
                (map 'vector
                     (lambda (x y)
                       (square (- x y)))
                     vec1
                     vec2))))

The key point is, that if you keep just the one rule that function arguments are idented vertically, you'll stop getting readability problems with to what function a thing is an argument.

You actually don't need an editor to manage parens - I learned this while solving exercises from SICP on paper - when you keep the proper pretty-printing you'll soon learn how to close parens without counting opening ones. You just look at the identation and you know how many levels you need to close.

TeMPOraL
Quoth TeMPOraL on June 08, 2010 @ 8:54 AM PDT

Quick note: in the comment above I meant that in Lisp pretty-print, function arguments are aligned vertically, not idented. Sorry for the mistake :).

Alpheus
Quoth Alpheus on November 30, 2010 @ 2:55 AM PST

I find it amusing that you linked to the "sweet-expressions" site, because I have found that proposal as one I'd especially would like to experiment with.

I discovered sweet-expressions when I was looking for a way to reduce parentheses for a lisp-based command prompt--I wanted to reduce the parentheses, and I felt that an indent-aware syntax was the way to do it.

I especially like one of the stated goals of sweet-expressions: to retain the power and flexibility of s-expressions, but to introduce changes to syntax. From the examples I have seen so far, I think they have done an admirable job so far: functional notation (eg f(x)), bracket-access for data, infix without precedence, nested lists designated by indentation, and full backwards compatibility with s-expressions.

Unfortunately, the reader available for Common Lisp is incomplete, so I have a lot of work to do before I can get to the point where I'll be able to experiment fully with this syntax.

As a mathematician, I'm impressed by the examples given, on how much more mathematical Lisp can look with these simple changes.

Lance Walton
Quoth Lance Walton on January 02, 2012 @ 6:19 AM PST

I agree.

In addition, I think that if keeping track of brackets is a problem in a function, then the function is probably too big and needs to be refactored.

LateButNotIrrelevant
Quoth LateButNotIrrelevant on March 08, 2012 @ 11:39 PM PST

I agree with all your points regarding the syntax of Lisp and if you know a thing or two about programming then you will begin to appreciate the purpose for parenthesis and prefix notation. I want to elaborate by saying that parsing is an absolute b!tch. The prettier your syntax is the more code you will need to parse all that pretty, sugary stuff. With an interpreted language this can slow down the performance of the interpreter. Using parenthesis and prefix notation like Lisp does is a very efficient way to parse and increases the performance of the interpreter. Many programmers have never tried writing a interpreter parser, so they cannot appreciate the beauty behind this design.

Eduardo Costa
Quoth Eduardo Costa on June 07, 2012 @ 6:39 AM PDT

This is an old thread, but I coundn't resist a comment. A lot of people complain about Lisp libraries. The one thing I like in Lisp are the libraries. Lisp has libraries for almost everything that matters. Quicklisp, asdf or libload add a library to your runtime system flawlessly. In Java, C or Python, it is a nightmare to run a library.

I use Lisp mostly for its libraries. I found libraries for circuit minimization, text editing, generating pdf, generating jpg, VLSI designing, symbolic computation (where else can I find a better package than Maxima?), running Python programs (clpython), databases (my firm homepage runs on Lisp), cryptography, running old Fortran programs in modern computers, publishing books in ancient languages (Hieroglyphs and Ancient Greek), scripts for Emacs (both in Common Lisp and elisp), converting Java programs to C, ocr, webservers, etc. Of course, Lisp has ffi libraries that give access to Python libraries, and C libraries.

When I am programming in Java or C, I miss Lisp libraries and features badly. My life would be much easier if I had a REPL in Java, or in C, with a incremental optimizing compiler, like sbcl or clozure common lisp.

Right now, I am writing a large Java program, and need to use source code written in Fortran. I also need scripts written in Python. A friend told me how to solve the problem in Common Lisp. He uses a package called clpython. After typing (ql:quickload :clpython), sbcl loaded my Python scripts without a single complaint. What is more, the script runs in sbcl twice as fast as in Python itself. A library called f2cl did the same thing to the Fortran source code. By the way, Python has a moving standard. My friend fixed clpython in minutes, to add features that did not exist in the version implemented by the clpython designers.

Arithmetic is a nightmare in the infix notation of Java. In my project, I need to do a lot of complex calendrical calculations, and financial mathematics. Casting (double) to (long) in Java, and similar operations is error prone. Programmers always get confused with the precedence rules. My friend finished a LISP prototype of our financial program (including converting 5000 lines of FORTRAN to Lisp, and 2000 lines of Python) in less than 4 hours. My team is working to do the same job in Java since december 2011. The client told us that the Lisp prototype was working perfectly well, but he could not accept the Java program, since it was not producing exactly the same results as the FORTRAN program.

I really envy Lisp programmers for working such a wonderful language. What matters is that, with the Lisp syntax, Lisp programmers can convert FORTRAN, Python, etc. easily to Lisp. The converted programs are compiled to code that run almost as fast as C code (sometimes, faster). They can use macros to create domain specific languages. They have an interpreter that runs as fast as compiled code (in fact, it is an incremental compiler), even when it is running Python code. The result: Lisp programmers are much more productive than Java programmers. I dare to say that a single Lisp programmer can code four times faster than a small team of three Java programmers, and two consultants.

My team has one Lisp programmer, four Java programmers, two Java gurus, one Common Lisp programmer, and one Scheme Programmer (Bigloo). The Lisp programmers write prototypes, and they get the job done in a very short time (one or two weeks is enough for most of jobs). Typically, it takes two months and four programmers to convert a two-week Lisp prototype to Java/Python.

Conclusion: I envy you people who program in Lisp. In particular, I envy your wonderful infix notation, that makes writing a library like f2cl or clpython so easy. Of course, I don't know Lisp. I guess that it is easy to write a Lisp program that compiles Python to Lisp because there are at least three Python to Lisp compilers.

One could say that it is easy to write a Python/Java program that executes Common Lisp. This is not true. Lisp is fast and efficient. I belive that Scheme is the only language that an efficiency issue (tail call optimization) is part of the standard. A large sbcl program can run almost as fast as C. Even so, the Lisp native code must be generated on the fly, to give the feeling of interpreted code. I am afraid that Python programmers cannot write such a code even for Python itself. Being a Python/Java programmer myself, I work with two Python compilers. Both are written in Lisp (one is written in Common Lisp, and the other is written in Scheme).

Victor Engmark
Quoth Victor Engmark on July 11, 2012 @ 12:52 AM PDT

Since this seems to be the only "living" discussion about "LISP syntax" according to Google, here's 2 cents from several short attempts at LISP/Scheme: The problem is neither the parens nor prefix syntax, but rather the minimalist syntax, like hash quotes #', hash parens #(, apostrophe parens '( and the tendency to shorten every name to the point of being unreadable (car, cdr, func, defun, setq). This means that to program efficiently you need to keep a very large list of translations in your head at all times. You can use quote and the like, but nobody seems to do it in actual code, and having alternatives for basic syntax like this makes the mental overhead even bigger.

LISP is already an immensely powerful language. If only it were as easy to read (not parse) as any modern language.