54 comments

[ 397 ms ] story [ 1927 ms ] thread
Well, yeah.

I think the popularity of lisp comes down to the hostility the mit ai lab had towards noam chomsky who in the 1960s spoke out about the vietnam war and thus bit the hand that funds cs research.

All other computer languages (except for forth) embraced formal grammar concepts but mit rejected them out of spite.

If mit had stopped burning the dragon book and embraced algol syntax we might have been spared the horrors of c, c++ and java but no, they just gave us 1 more reason rt 128 is a boulevard ofbroken dreams.

Huh. I was around the AI Lab in the late 1970s -- as an undergrad -- and I don't recall hearing anyone talk about Chomsky in the way you imagine. DARPA funding was still flowing rather freely, it seemed to me, well into the mid-1980s. I don't recall anyone suggesting that there would have been yet more DoD money if it hadn't been for Chomsky. And the grad student I did some work for, who was working on natural language parsing, was clearly intimately familiar with Chomsky's ideas on transformational grammar and referred to them throughout his dissertation.

So this isn't ringing true for me.

I also recall Gerry Sussman speaking quite highly of Algol 60.

No, I think you're quite wrong: the reasons for the popularity of Lisp at the AI Lab have to do with its actual advantages over other languages for the kinds of problems they were working on.

And there is an example of a language in the MIT tradition with infix syntax: Dylan. Great language, but wasn't in the right place at the right time to catch on.

Was Sussman talking about the syntax, or things like lexical scope, which he and Steele introduced to the LISP world with Scheme in the mid-70s?

About the only relevant negative thing I remember being said about Chomsky in a period just after your's was Marvin Minsky saying he saved someone from going down a rabbit hole following Chomsky's work. But that was a judgement of merit of his linguistics work, not his politics.

Well, the lexical scope, certainly, but I don't recall him disparaging the syntax.

I don't recall any burning of Dragon Books. Nor was Vaughan Pratt tarred and feathered for releasing CGOL, which allowed one to write Lisp in infix syntax. People were aware of it, and a few people used it, but it didn't catch on in a big way. I don't think this was for ideological reasons; I think it was simply that most people writing Lisp (myself included) found that with proper editor support, editing fully parenthesized code is easy and pleasant -- more so, in many cases, than editing infix code. That is the fact that many non-Lispers cannot believe could possibly be true. And yet over and over again, people who learn Lisp report that it is.

Poe's law? Honestly can't tell.

Perhaps lisp programmers like the idea of composition, and decades later we still have no useful method for composing formal grammars? When we instead use a uniform tree structure and replace syntax with vocabulary, the problem disappears, and we only need to be concerned with composing the semantics of different "languages".

Or maybe they also like being able to quote some tree structure and treat it as code, or quote some code an treat it as data too - without the need for some genius to create an "API" to serialize and deserialize the data, and re-implement the compiler/interpreter.

Oh, if you need a feature, you could always ask the developers of your formal syntax to add it to the language, then wait a few years for the next revision to come around.

The abstract syntax was intended to be used writing programs until designers could get around to creating a concrete syntax with human-readable punctuation (instead of Lots of Irritating Silly Parentheses), but programmers soon got used to programming directly in abstract syntax.

That's some programmers who got used to the syntax. It may be absolutely true that once you get used to LISP's syntax, it is better than any other. The problem is that since one is dealing with human beings, and with human beings you have the power of first impression and the tendency to make snap decisions based on these, people initial difficulty in grokking LISP's syntax is always going to be a hurdle for the language.

Is grokking Lisp's parenthesized s-expressions actually difficult though? I think that the real problem is that developers believe that they will find it difficult before they try it, rather than actually finding it difficult when they eventually do try it. I don't think I've ever picked up another class of languages faster; even python took more effort from me.

Basically, I think it's a marketing problem.

We're hard-wired for Lisp. Broca's area 44,45 and 47 are responsible for processing hierarchical structures.[1] That's why it's so easy to reason about Lisp code.

[1] http://www.letras.ufrj.br/poslinguistica/recursion/papers/17...

I think that the real problem is that developers believe that they will find it difficult before they try it, rather than actually finding it difficult when they eventually do try it.

That is pretty much what I meant. But given that the language expressions people are exposed to in their lives before LISP inherently aren't going to look like LISP, this a "marketing problem" that isn't going to go away. LISP doesn't look like natural language, that won't change and will always be hard for people to get over.

I have to respectfully disagree. I have coded for years in a lot of C-style languages, mainly C, Java, Python, Ruby & JavaScript and I've been struggling with the Clojure book (and various tutorials) for over a year. It's not just marketing, it's a very different mindset and one I'm not convinced is ever going to appeal to a large class of smart programmers (yes I guess I'm saying I don't think I'm dumb and hope I'm not alone in this feeling).

I've heard Lisp described as an autistic language, and I think there's something to that. I don't think it's for everyone. I'm not on board that macros, homoiconicity and some of the other stated benefits of lisps are worth 'giving up syntax' for and I am far from convinced that lisps are the future of programming.

I'm a huge fan of Rich Hickey and I want to love Clojure, I just can't. It's not for me and it's not a marketing thing. Rich is the best marketing a language could hope for.

Are you using automatic indentation, parenthesis matching, and highlighting the current s-expression? Lisp environments have, or can be given, a lot of tools to make the syntax easier to follow at first.

You may already have heard about those things - but I just thought I'd mention them on the off-chance you haven't.

Personally I find the syntax a lot easier to read - less giving up syntax than eliminating what's always looked like a bit of a mess to me ^^ Though, horses for course maybe, as you say.

I'm a fan of Rich Hickey, too. And I think Clojure is a solid language. But I wouldn't suggest Clojure as the entry point when seeking a overall understanding of Lisp. There's too much baggage and history swirling around it for explanations ever to be comfortable - e.g. even if Rich Hickey always makes convincing arguments, it's important to note that they are always arguments.

That is there always seems to be at least as much of a subtext of Clojure defining itself by what it isn't as an explicit statement of what Clojure is. So much of what is said about it is said in the context of "Clojure is not Java, or Haskell, or Scala, or Scheme, or Common Lisp" and because that is so much a part of its culture, it has details drawn from 'the best parts' of each and mashed up.

Like Common Lisp, it is a language for working programmers and will trade practical accretion over striving for internal conceptual consistency. Unlike Common Lisp or Scheme, it doesn't have the sort of simple core that lends itself to tutorials from first principles and even if it did, the community tends to be experienced where just jumping into the middle is more the norm.

That's nothing against Clojure. It's just that any sort of gentle introduction to Lisp is probably better sought in those places where it already exists - SICP or the Racket ecosystem or Practical Common Lisp or PG's On Lisp are probably better introductions to what makes Lisp different. Clojure is probably a better second Lisp dialect for many people once they are ready for full tilt production code.

In learning Clojure first then Racket, it struck me how many good ideas came from racket.. and now how many are still being mined - typed racket being the obvious one.
I don't know how much Rich Hickey used Racket, but he used Common Lisp for several years and wrote some complex libaries for it. There is also a sketch of Clojure early on written in Common Lisp.
Racket started out as a Scheme, and Clojure has mined quite a bit from Scheme. Both are Lisp-1s, loop/recur, not accepting a lot of mainline LISP (e.g. Common Lisp nowadays) baggage, etc.
Actually there is not much Clojure got from Scheme. Lisp 1 is not tied to Scheme. loop/recur is much less powerful than Scheme's TCO.
Lisp-1 is pretty firmly tied in most people's minds to Scheme: at the very least the paper that coined the terms (http://www.nhplace.com/kent/Papers/Technical-Issues.html) ascribed it to Scheme, and as far as I know it first came from Scheme (although it's so easy to create a low performance Lisp I wouldn't be surprised if that had been tried before).

loop/recur is of course much less powerful than TCO, because the JVM doesn't natively support it (it's not trivial, security wise). There are three other Lisps on the JVM that I know of: SISC Scheme is mostly dead but does TCO at a cost in speed, Kawa Scheme has as of late added fine grain control over TCO, and Armed Bear Common Lisp doesn't try, as Common Lisps are not required to.

But loop/recur sure looks to be ultimately inspired by Scheme style use of TCO; I just did a set of functions using it for the first time and everything I learned from SICP/6.001 applied and made that part of it trivial.

Haskell also has only one namespace. I propose that Clojure took it from there, including persistent data structures, lazy data structures, ...

> But loop/recur sure looks to be ultimately inspired by Scheme style use of TCO;

To me it looks more like ancient Lisp with prog and goto.

    (defun foo ()
      (prog ((a 1))
        start
        (print a)
        (when (< a 10)
          (incf a)
          (go start))))
Old Lisp code is full of that. It's basically what LOOP/RECUR provides.
That's the advantage of Racket's close relationship with academia...'Implementing x in Racket' is publishable and 'A y Library for Racket' is a Master's Degree project.
FWIW, you're learning two major paradigms at once: the immutable/functional paradigm and a Lisp, and Clojure itself has very strong opinions about the former. You'll get a very different feel from, say, Racket.

Is there something in particular you're having a hard time with, out of curiosity? I don't consider myself particularly brilliant but I didn't have a year's worth of trouble with Clojure.

That's the wrong metric.

I learned Scheme over 20 years ago and it wasn't that hard to use it for small college projects. But that's different from being comfortable working with large code bases full of unfamiliar code.

Languages shouldn't be judged by how easy it is to write code, or read your own code, but rather how easy it is to jump into someone else's project and figure out what they did. The level of understanding should be enough to see security bugs when they screwed up.

I think those problems stem from the embrace of metaprogramming, the creation of DSLs, and language oriented programming. I don't think that Lisp's typical lack of syntax is to blame there.
Well, Lisp's lack of syntax stands in the way of using syntax to tell a story.

Horrible as c++ might be in many respects, the elaborate and somewhat stereotyped syntax of the code some random person wrote does tell a story.

If the code uses the horrific "one big loop" convention, it's fairly easy at least to get that that is what's going on.

I've only occasionally scanned Lisp code but in my experience of this, it seems like the formatting of the code doesn't a clue about the programming idiom being used. Admittedly, part of this is that Lisp allows more and more powerful idioms. This part seems really cool by itself.

Despite that coolness, I think one has to admit there's a cost here, the cost of a large block of code not being graspable by an outsider.

Nearly my entire professional career has been spent using languages other than lisps, but I am not really sure what you mean by use of syntax telling a story.

Perhaps the subset of C++ used reveals something about the development team that wrote it I guess? But there are certainly analogous things in lisp. Is the code macro heavy or light? Was the developer trying to treat the language like an imperative language, or functional? Massive monolith functions, or many small almost mathematical functions? Comments, or no comments?

I think that C++ and Lisp might actually be relatively unique in that respect. You typically don't see much variety in Java (beyond "This code was clearly written by a C developer who wishes he could just use C for this", which comes through loud and clear sometimes), and even less in Python.

I'm a C/C++/Java guy. I didn't find the idea of Lisp or the basic syntax that hard.

Where I ran into trouble was not the strangeness of the syntax, but the sparseness: "It takes a macro to write a decent loop? Isn't that telling you that your basic syntax is ridiculously impoverished?" I mean, yes, you can implement absolutely anything, but in the bare syntax, you're given absolutely nothing.

Second trouble spot: Lack of static types. It makes it hard to reason about a function if I don't know what's passed into it. I have to read the code and guess, from what it does, what the form of the arguments were supposed to be. And every caller has to know it, and to follow it. If they don't, chaos will ensue, unless the function defends itself by checking the arguments. But that means verifying, by examination, that what got passed in is what was expected - not the easiest task.

Now, Lisp people say that this isn't a problem in practice, because as you play with the code, if the wrong thing happens it will throw you into the debugger. But different code paths wind up getting exercised in the wild, and I've spent most of my career in embedded systems. Dropping into a debugger is not an acceptable bug-handling strategy in my world. I'd rather have the compiler catch them.

You don't need to write macros to write a loop. What you probably do need is macros to create a new looping construct of your own... but it's not practical or idiomatic to do that in the first place in other languages.

If you want an "until" construct in Lisp, you can create one with macros easily and doing so would be considered fairly kosher. If you want an "until" in C, you could swing it with macros, but you'd be told to buzz off when it came time to receive code reviews for it.

In common lisp, a for loop is reduced to a goto internally via a macro which manipulates the syntax tree. In C, a for loop is internally reduced to a goto after the code is transformed into a syntax tree (manipulated by a non-standard and ad-hoc macro implementation). The difference here is that C must first make the syntax tree before it reduces the tree while CL reduces it immediately (since lisp code is already a tree).

All languages must reduce to a limited ISA of primitives (or conversely, all HLL are built on small ISAs). Lisp does a lot of this conversion early on (because it can) while C does this much later (because it can't do it early). You're simply quibbling about how soon to do this conversion. LLVM does the same thing as lisp in that it reduces a seemingly large language into a small set of constructs (and then works to optimize this small core language). I would argue that a smaller core language is better because it is easier to reason about and easier to optimize.

As to embedded, iRobot corporation created a lisp variant called L (based on a subset of common lisp) to use on their embedded processors via a bytecode VM.

http://www.cs.cmu.edu/~chuck/pubpg/luv95.pdf

Check out shen lisp (link below). It has (to my knowledge) the world's only Turing complete static typing system. Racket also has a static variant. Common lisp can be made into the equivalent of statically typed if you (declare) all variables and tell it to fully optimize.

http://shenlanguage.org/

Kind of funny that people in the embedded area use C, which has a very weak type system and the result of using C is usually unsafe (no matter how programmers try) - even though its supposed to be compiled with static type checking.

> "It takes a macro to write a decent loop?"

That's the usual way to introduce a LOOP. As most Lisp implementations are written in Lisp, most syntactic constructs are macros anyway - whether they are at the language or the user level. For many Lisp systems there is really no distinction between both.

> Dropping into a debugger is not an acceptable bug-handling strategy in my world.

For embedded programming Lisp can have a lot of problems:

* lack of compile time safety

* the need for Garbage Collection

* no low-level machine types

* more...

Since the nature of 'embedded' is changing, some of that might no longer be such a big problem. In some areas 'embedded' systems are suddenly actually full-blown connected computers.

"preventing advancement" is a pretty bold assumption.
What most people have with Lisp syntax, I have with Objective-c. I am mostly blind to syntax (I skip from language to language fast reading/writing) except for some esoteric languages (like http://www.hakank.org/k/) AND Objective-c. I find it extremely annoying to read while I do it every day. Writing is better for some reason, but far removed from other languages. So I see why some people would not like Lisp syntax while I find it very pleasant/enjoyable to read.
I have yet to hear a good explanation why homoiconicity is a good thing or in any way easier to learn. My main problem is that you have to know all the same things, but they become unknown unknowns. Not being able to tell at a glance that the argument list in a lambda expression, as one of the most common examples, is doing something other than execute code is very confusing if you're expecting everything to follow the (func arg1 arg2) pattern. On the other hand, when you encounter different syntax, it's immediately obvious that you need to know something else - a known unknown, which is easier to correct.
The main advantage of homoiconicity is that it lets you write macros more easily and safely. This Stack Overflow answer lists some reasons why this is so: http://stackoverflow.com/a/9146303/578288.

Macros are good because they let you refactor repetitive bits of code that functions can’t refactor. With the extra refactoring, your program is simpler and easier to modify, because its abstractions are more apt.

I think part of the problem is that Lisp is an incredibly broad language in terms of its capabilities.

The macro system can be extremely powerful and when abused, is a nightmare to decipher. But. In the real world, I've rarely ever encountered someone who has actually programmed in such a bad style. A macro to me is almost no different than a function declaration (ie. (func arg1 arg2)), I just have to bear in mind whether it's being executed at compile or run time. Frequently I find a macro unnecessary and replace it with a straight function definition.

My golden rule is to avoid nesting macros in my own code (libraries are a different matter - wrap 'em in error handlers). If I stick to that, it becomes very simple and very powerful. It's not a very strict rule, but it is a helpful one as it reduces the general level of abstraction to a manageable level, while still being useful. Due to Lisp's flexibility, I think you have to maintain stricter coding standards than you perhaps would otherwise (but also know when to break them). If you create the right macros, you can save hundreds of lines of code and make the codebase far more maintainable.

A good example I had recently was for a website; I had a template macro for all the <doctype>/<head>/css/js and had the navbar, footer, general layout in the template as well. Then I had each webpage defined as a function that called the template macro and then inserted the rest of the <body> into the page. (This saved a ton of code in terms of templating; it could probably be done in other languages too, but you'd have to squeeze it into OO format or something)

This was all well and good, I had about 20 pages done before I ran into a bug. In some other languages, you would then go round adding a debug line/condition handler to every function, but instead I added it to the main template macro just once and it handled all the functions. Even better, the macro system and condition handler allowed me to deal with the code both before and after it had been compiled. I then passed the error up the stack from the function to the macro's handler, had the handler choose a fix (recompile the page function with different params), then send it back to the function (without ever exiting the stack) and carry on as if nothing happened. The users see nothing.

I don't use a lot of the things Lisp can do (eg. I can't remember the last time I made a function generate another function and return it), but it works exceptionally well for what I do use (currying, composing, macros and more).

I don't know if "homoiconic" is the right term for the qualms you have, since Prolog, Mathematica, Julia, etc. have plenty of additional syntax, but are considered homoiconic.

http://en.wikipedia.org/wiki/Homoiconicity#Examples

...does homoiconicity really mean anything more than a language has a "read" procedure available?

I don't think I've heard anyone argue that homiconicity makes Lisp easier to learn. I would characterize that as an advanced concept— it only becomes relevant once you start learning about macros.

As far as Lisp's syntax itself, the lack of special cases means there's less to learn. Myself, I like some of the sugar you get in Clojure for hashes, vectors, sets, etc.

As for macros themselves, ostensibly you don't need to know the implementation details of every macro any more than you need to understand what executing a Java method does in terms of JVM bytecode. In practice sometimes you'll goof up and try to map a macro over a list. Depending on your Lisp implementation, the mistake should be obvious. And depending on your editor, it may even highlight some or all macros differently.

Also, Racket also has a different approach than some of the Lisp reader manipulation you see in Common Lisp. We're getting outside my familiarity here though.

Not everything is follwing a (func arg1 arg2) pattern.

For example a LET binding is following a (LET ((var1 binding1) (var2 binding2)) body) pattern.

Or in Clojure, I'm starting to accept that this common pattern is a good thing:

  (let [var1 binding1
        var2 binding2]
     body)
I have yet to see any data that supports ANY programming syntax as easier to learn or in any way a good thing.

Knowing a few C-style languages, a few lisp style languages, and a few ML style languages, I have found unsurprisingly that the language I'm using most becomes the easiest to read.

But since all we have is anecdotia and talks about our feelings, cracks knuckles, I'll give my two cents.

I think ML style is the easiest to _learn_ to read. It's sparse, simple, and almost always obvious. It's probably my favorite to read, and I usually find myself able to read it quickly.

My favorite to write and edit is a lisp style. With paredit and vim, I feel like I can edit code effortlessly. Every time I'm back in a C or ML descendant, I find I'm always wishing I could easily grab this expression or that parameter, and whoops, don't forget that comma there, nope this line it is a semicolon, nope this line it's a period. The irregular shape of the code with a different character for each concept (period for chained method call, comma for chained list or argument, semicolon for end of line, etc) makes it very hard to edit quickly. With so many different representations it is hard to add keyboard macros to help you structure code.

Specifically, in C# and JS, I always feel like I'm just pounding the text like a blacksmith, with sparks of commas, periods, semicolons, colons, brackets, square brackets, and angle brackets flying around. With lisps, it's usually just parens, and with paredit and Vim's in/a parens commands, they mostly work for me, not against me.

That same simplicity of representation is why macros are so fluid and simple in lisps. Can macros exist in other styles? Theoretically, yes, but all the issues I mentioned would be barriers in the way.

What I think this is missing which was a huge part of the SICP course is that Lisp is probably the best language to write your own language in with a custom syntax tailored for the problem space you're working on. Even if it isn't trivial to do.

An example is Clojure's Hiccup[0] where there's a whole new syntax for dynamic HTML generation. It's not a full new Turing-complete language, but it's a custom syntax and vocabulary that illustrates Lisp's extensibility (a sample of Hiccup in action is linked below, though it isn't mine.)

[0] - https://github.com/yokolet/hiccup-samples/blob/master/src/hi...

This one of the reasons why, as a Lisp programmer, I don't care much for Clojure. Three different bracketing constructs when one would do just fine. Now I have to go look up the difference between () and {} and [] just to emit some HTML.
No, you wouldn't. Idiomatically [] is used for declarative structures for consumption by macros (like argument lists) and {} is obviously a map, and is used for any key/value pairs. So the HTML DSL linked above is the most intuitive one to a clojure programmer with regard to the data structures used. Adding maps and vectors to be first-level syntax to clojure is one of my favorite things about the language.
As an old Lisp hand, while I'd prefer those declarative structures to be in old fashioned parens, it's not too obnoxious and has some clarity value in adding it as language syntax. But I agree 100% with the value of adding to the first-level/first-class syntax, it's both clear and very convenient.
That's funny. This is one of the reason why I don't care much for Common Lisp. Hashtables in particular are common as mud in programming, but I have to work with a clunky interface specific to each abstraction. Ironically this puts CL closer to Java and C++ than the likes of Python and Ruby.
Hashtables are common, if one does not have other choices.

For many uses of hashtables, lists are just as good.

When I look at that sample, what strikes me is how much the "custom syntax" still looks like a bunch of S-expressions.

How much flexibility does LISP really give you here? For example, say I wanted my DSL to use Python-style significant whitespace instead of brackets. Does LISP make that easy, or is my DSL restricted to using stuff that looks like S-expressions?

http://readable.sourceforge.net/

from this:

(define (factorial n)

  (if (<= n 1)

    1

    (* n (factorial (- n 1)))))
to this:

define factorial(n)

  if {n <= 1}

    1

    {n * factorial{n - 1}}
and if you want to use parens, they just work (you can mix and match the two whenever you want without issue). That said, even with such things available, most lisp programmers opt to use parens.
It might not be easy, depending. Without too much trouble you could write a macro for this:

    (my-macro "
    foo
       bar
    baz beez
       zang
          dang
          bang")
and have the macro parse the string manually into something the eval/apply loop understands. But I think it might get funky pretty quick, and you'll likely lose a lot of power in the process.

The example of Hiccup above doesn't add anything new to Clojure's syntax, the DSL is all legal Clojure data structures. That way it inherits all of the power of the underlying language, like if you want to dynamically generate new HTML - that functionality comes from Clojure. But doing that while modifying the syntax for meaningful whitespace wouldn't be easy.

Racket is somewhat unique in this respect, but it allows you to create dramatically different languages as DSLs.

Consider this example of the experimental "2d" syntax:

  #lang unstable/2d racket
  (require unstable/2d/cond)
 
  (define (same? a b)
    #2dcond
    ╔═════════════╦═══════════════════════╦═════════════╗
    ║             ║       (pair? a)       ║ (number? a) ║
    ╠═════════════╬═══════════════════════╬═════════════╣
    ║ (pair? b)   ║ (and (same? (car a)   ║     #f      ║
    ║             ║             (car b))  ║             ║
    ║             ║      (same? (cdr a)   ║             ║
    ║             ║             (cdr b))) ║             ║
    ╠═════════════╬═══════════════════════╬═════════════╣
    ║ (number? b) ║          #f           ║   (= a b)   ║
    ╚═════════════╩═══════════════════════╩═════════════╝)
Yes, that big ascii-art graph is actually part of the code, not some sort of comment. The 2d syntax allows you to create ascii art truth tables which contain in them code (in this case, in the traditional paren'd style.)

(See http://docs.racket-lang.org/unstable/2d.html for a better explanation and more examples.)

Alternatively, here is an example of typed racket using sweet expressions:

  #lang sweet-exp typed/racket

  define: fact([n : Integer]) : Integer
    if zero?(n)
       1
       {n * fact{n - 1}}
(https://github.com/takikawa/sweet-racket)*
The abstract syntax was intended to be used writing programs until designers could get around to creating a concrete syntax with human-readable punctuation (instead of Lots of Irritating Silly Parentheses), but programmers soon got used to programming directly in abstract syntax.

Perhaps it was, but..

1) The nature of research is so that you can't always predict in which way your invention will be useful. To me and many others it seems lisp syntax is quite handy.

2) If we take Clojure for the sake of example, we'd see that it comes with some neat macros which are important part of the language. Those can be viewed as mentioned concrete syntax elements built upon the abstract syntax. Punctuation's been improved as well.

The biggest proof of the overwhelming preference for parens can be found in the dylan programming language. Despite having M-expression syntax (in fact, the original spec was prefix lisp), the same CLOS object system, and even a macro system, the language has gone nowhere with lispers. More interesting is that dylan was also unpopular with ALGOL programmers. The existence of "sweet expressions" (M-expressions) allowing infix syntax in existing lisp languages further removes this as the main issue.

The worst answer as to why people hate lisp is the "too many parenthesis" argument. C-style programmers are just as happy to mash 5-6 paren/curly-brace sets together in one line. The only major difference is location. For example, (if test (<result>) (<alternate>)) vs if(test){<result>}else{<alternate>}. In addition, the only reason the closing parens are on a separate line in C and the same line in lisp is convention.

I suspect the biggest barrier to ANY language is having a non-C syntax style rather than infix vs prefix or parenthesis. The inertia is simply too great.