27

Three lispy homoiconic languages, Dylan, Julia and Seph all moved away from leading parenthesis - so a hypothetical function call in Common Lisp that would look like:

(print hello world)

Would look like the following hypothetical function call

print(hello world)

in the three languages mentioned above.

Were Clojure to go down this path - what would it have to sacrifice to get there?

Reasoning: Apart from the amazing lazy functional data structures in Clojure, and the improved syntax for maps and seqs, the language support for concurrency, the JVM platform, the tooling and the awesome community - the distinctive thing about it being 'a LISP' is leading parenthesis giving homoiconicity which gives macros providing syntax abstraction.

But if you don't need leading parentheses - why have them? The only arguments I can think of for keeping them are

(1) reusing tool support in emacs

(2) prompting people to 'think in LISP' and not try and treat it as another procedural language)

Frames Catherine White
  • 27,368
  • 21
  • 87
  • 137
hawkeye
  • 34,745
  • 30
  • 150
  • 304
  • 6
    A big part of the lisp aesthetic is the trivial parseability and usability as data of the code; you'd lose some of that. – zmccord Mar 02 '12 at 12:19
  • Function application is just one of many possible forms. Are you proposing to treat them differently? Clojure already did a terrible thing, abolishing cons cells. Going any futher would totally ruin the language. – SK-logic Mar 02 '12 at 12:48
  • 4
    See also http://stackoverflow.com/questions/643892/fixing-lisp-syntax. The question reminds me of a Pascal developer I knew who, when faced with having use C, wanted a set of macros that made C more Pascal-like. I think there is always a temptation to reduce your discomfort with something new by forcing it be more like familiar. And yet sometimes it is good for you to approach something different on its own terms. – user100464 Mar 02 '12 at 15:03
  • 8
    If it's that trivial, why would you want it? Is "print(hello world)" really that much easier to read than (print hello world)? What about +(1 2 3)? that's starting to look odd. Or +(1 2 3 /(2 4))... Such a trivial change doesn't do much - and as others pointed out, people will likely ask for infix operators and such. The sacrifice would be giving up the beautiful and very practical simplicity of lisp syntax, only for the benefit of those new to lisp who don't want it to look lisp-y. If you stick with s-expressions, you won't even notice the syntax a couple of months from now. – Gert Mar 02 '12 at 17:34
  • I hear you that I didn't cover off the "why" of this. The question was a hypothetical - if three other individual language designers included this, surely there is some merit. – hawkeye Mar 02 '12 at 22:42
  • 3
    @hawkeye- I think the responses of @gertalot and @mikera address the real ``why'' behind this decision. Inasmuch as syntax is arbitrary, it shouldn't matter. Of course, when one considers the extent to which regular syntax reduces the complexity of code that transforms code, syntax really matters. And so, the optimal syntax depends on the optimality criterion. The syntax adopted by Dylan and like is optimal in that it allows for easy adoption by s-expression n00bs. It is suboptimal for programmers writing macros. They key parameter, I think, is the timescale of n00bs groking s-expressions. – Gabriel Mitchell Mar 03 '12 at 03:39

9 Answers9

25

(Credit to andrew cooke's answer, who provided the link to Wheeler's and Gloria's "Readable Lisp S-expressions Project")

The link above is a project intended to provide a readable syntax for all languages based on s-expressions, including Scheme and Clojure. The conclusion is that it can be done: there's a way to have readable Lisp without the parentheses.

Basically what David Wheeler's project does is add syntactic sugar to Lisp-like languages to provide more modern syntax, in a way that doesn't break Lisp's support for domain-specific languages. The enhancements are optional and backwards-compatible, so you can include as much or as little of it as you want and mix them with existing code.

This project defines three new expression types:

  • Curly-infix-expressions. (+ 1 2 3) becomes {1 + 2 + 3} at every place you want to use infix operators of any arity. (There is a special case that needs to be handled with care if the inline expression uses several operators, like {1 + 2 * 3} - although {1 + {2 * 3} } works as expected).
  • Neoteric-expressions. (f x y) becomes f(x y) (requires that no space is placed between the function name and its parameters)
  • Sweet-expressions. Opening and closing parens can be replaced with (optional) python-like semantic indentation. Sweet-expressions can be freely mixed with traditional parentheses s-expressions.

The result is Lisp-compliant but much more readable code. An example of how the new syntactic sugar enhances readability:

(define (gcd_ a b)
    (let (r (% b a))
        (if (= r 0) a (gcd_ r a))))

(define-macro (my-gcd)
    (apply gcd_ (args) 2))

becomes:

define gcd_(a b)
    let r {b % a}
        if {r = 0} a gcd_(r a)

define-macro my-gcd()
    apply gcd_ (args) 2

Note how the syntax is compatible with macros, which was a problem with previous projects that intended to improve Lisp syntax (as described by Wheeler and Gloria). Because it's just sugar, the final form of each new expression is a s-expression, transformed by the language reader before macros are processed - so macros don't need any special treatment. Thus the "readable Lisp" project preserves homoiconicity, the property that allows Lisp to represent code as data within the language, which is what allows it to be a powerful meta-programming environment.

Michael Geary
  • 28,450
  • 9
  • 65
  • 75
TuringTest
  • 351
  • 3
  • 4
  • 3
    if you're all fired up, it always struck me that racket (a scheme that supports multiple "languages") would be a good place to implement this - https://en.wikipedia.org/wiki/Racket_features#Language_Extensions – andrew cooke Jul 10 '13 at 00:30
  • 1
    "in a way that doesn't break Lisp's support for domain-specific languages." This is most important. Syntax is light, so you can easily connect to other universes like logic programming, theorem proving and even typing etc. without grafting something completely new onto the existing syntax or suddenly having to handle different types of source files. Although the editors need to be updates as syntax highlighting cannot cope any more. – David Tonhofer Jan 28 '20 at 07:51
23

Just moving the parentheses one atom in for function calls wouldn't be enough to satisfy anybody; people will be complaining about lack of infix operators, begin/end blocks etc. Plus you'd probably have to introduce commas / delimiters in all sorts of places.

Give them that and macros will be much harder just to write correctly (and it would probably be even harder to write macros that look and act nicely with all the new syntax you've introduced by then). And macros are not something that's a nice feature you can ignore or make a whole lot more annoying; the whole language (like any other Lisp) is built right on top of them. Most of the "user-visible" stuff that's in clojure.core, including let, def, defn etc are macros.

Joost Diepenmaat
  • 17,633
  • 3
  • 44
  • 53
  • :) Agree you can't make people happy. I'm assuming you'd keep macros, and I think you're saying "well you'd have to rewrite all these core language macros". But the point is that someone decided this was worth it on at least three different languages. My question wasn't the why but the what. – hawkeye Mar 02 '12 at 22:41
14

Writing macros would become much more difficult because the structure would no longer be simple you would need another way to encode where expressions start and stop using some syntactic symbol to mark the start and end of expressions to you can write code that generates expressions perhaps you could solve this problem by adding something like a ( to mark the start of the expression...

On a completely different angle, it is well worth watching this video on the difference between familiar and easy making lisps syntax more familiar wont make it any easier for people to learn and may make it misleading if it looks to much like something it is not.

even If you completely disagree, that video is well worth the hour.

Arthur Ulfeldt
  • 90,827
  • 27
  • 201
  • 284
13

you wouldn't need to sacrifice anything. there's a very carefully thought-out approach by david wheeler that's completely transparent and backwards compatible, with full support for macros etc.

andrew cooke
  • 45,717
  • 10
  • 93
  • 143
5

You would have Mathematica. Mathematica accepts function calls as f[x, y, z], but when you investigate it further, you find that f[x, y, z] is actually syntactic sugar for a list in which the Head (element 0) is f and the Rest (elements 1 through N) is {x, y, z}. You can construct function calls from lists that look a lot like S-expressions and you can decompose unevaluated functions into lists (Hold prevents evaluation, much like quote in Lisp).

There may be semantic differences between Mathematica and Lisp/Scheme/Clojure, but Mathematica's syntax is a demonstration that you can move the left parenthesis over by one atom and still interpret it sensibly, build code with macros, etc.

Syntax is pretty easy to convert with a preprocessor (much easier than semantics). You could probably get the syntax you want through some clever subclassing of Clojure's LispReader. There's even a project that seeks to solve Clojure's off-putting parentheses by replacing them all with square brackets. (It boggles my mind that this is considered a big deal.)

Jim Pivarski
  • 5,568
  • 2
  • 35
  • 47
2

I used to code C/C#/Java/Pascal so I emphasize with the feeling that Lisp code is a bit alien. However that feeling only lasts a few weeks - after a fairly short amount of time the Lisp style will feel very natural and you'll start berating other languages for their "irregular" syntax :-)

There is a very good reason for Lisp syntax. Leading parentheses make code logically simpler to parse and read, by collecting both a function and the expressions that make up it's arguments in a single form.

And when you manipulate code / use macros, it is these forms that matter: these are the building blocks of all your code. So it fundamentally makes sense to put the parentheses in a place that exactly delimits these forms, rather than arbitrarily leaving the first element outside the form.

mikera
  • 105,238
  • 25
  • 256
  • 415
2

The "code is data" philosophy is what makes reliable metaprogramming possible. Compare with Perl / Ruby, which have complex syntax, their approaches to metaprogramming are only reliable in very confined circumstances. Lisp metaprogramming is so perfectly reliable that the core of the language depends on it. The reason for this is the uniform syntax shared by code and data (the property of homoiconicity). S-expressions are the way this uniformity is realized.

That said, there are circumstances in Clojure where implied parenthesis is possible:

For example the following three expressions are equivalent:

  1. (first (rest (rest [1 2 3 4 5 6 7 8 9])))
  2. (-> [1 2 3 4 5 6 7 8 9] (rest) (rest) (first))
  3. (-> [1 2 3 4 5 6 7 8 9] rest rest first)

Notice that in the third the -> macro is able in this context to infer parentheses and thereby leave them out. There are many special case scenarios like this. In general Clojure's design errs on the side of less parentheses. See for example the controversial decision of leaving out parenthesis in cond. Clojure is very principled and consistent about this choice.

rplevy
  • 5,393
  • 3
  • 32
  • 31
1

Interestingly enough - there is an alternate Racket Syntax:

@foo{blah blah blah}

reads as

(foo "blah blah blah")
hawkeye
  • 34,745
  • 30
  • 150
  • 304
0
Were Clojure to go down this path - what would it have to sacrifice to get there?

The sacrifice would the feeling/mental-modal of writing code by creating List of List of List.. or more technically "writing the AST directly".

NOTE: There are other things as well that will be scarified as mentioned in other answers.

Ankur
  • 33,367
  • 2
  • 46
  • 72