
Sweet-expressions: A readable format for Lisp-like languages - evanrmurphy
http://www.dwheeler.com/readable/sweet-expressions.html
======
Zak
Somebody has invented a more conventional-looking syntax for Lisp every couple
years since John McCarthy first suggested M-expressions. Nobody[0] has ever
cared enough to use any of them.

People who "get" Lisp get over any aversion to the syntax, and usually even
come to appreciate it. People who can't get over the syntax never actually get
Lisp.

[0] For large values of nobody

~~~
derefr
Because the people who "get" Lisp are almost always theoreticians who know
what they want to code before they code it. They use Lisp as a write-only
language. Meanwhile, working programmers avoid it, because it's very hard to
step into someone else's Lisp codebase and understand it (and not just because
of the fact that anything could mean anything due to macros—code is already
visually indistinguishable from data without them.)

Languages, just like any other computer software, have a User Experience: the
experience of programming in them. For example, the usual justification people
give for why they like Ruby is that it has a good UX. There's no theoretical
purity there, they just say it's "fun to code in."

Lisp, meanwhile, does not obey any of the principles of HCI that have been
discovered in the last 30 years (how could it? It was invented before them!)
There's a large gulf of evaluation stopping a programmer new to a Lisp
codebase from understanding what their changes will do to it. UI design is
about human psychology, not theoretical purity; solving this problem might
seem like "papering over" the purity of the language from a theoretical
perspective, but when doing actual comparative usability studies[1], it would
be clear that the "papered-over" version would have something going for it
that the theoretically-pure version does not.

[1] A comparative usability study on a language is very simple to perform: you
basically print out some code samples, let people with no experience in the
language (but general programming experience) read them for a set time period,
and then evaluate their comprehension.

~~~
raganwald
_A comparative usability study on a language is very simple to perform: you
basically print out some code samples, let people with no experience in the
language (but general programming experience) read them for a set time period,
and then evaluate their comprehension._

That is just _one_ axis of usability, optimizing for comprehension by someone
unfamiliar with the language. Usability is also optimizing for the experienced
programmer. Some designs do a good job for both, some work well for one at the
expense of the other.

Hef Raskin had some interesting things to say about this:

<http://www.asktog.com/papers/raskinintuit.html>

~~~
euccastro
Also, people with 'no experience in the language', but with 'general
programming experience' will be primed with the conventions of mainstream
languages and biased against s-expressions.

(Btw, it's _J_ ef Raskin.)

~~~
derefr
By "general programming experience," I didn't mean " _mainstream_ programming
experience," but rather "having been given a survey of techniques for
programming in iterative, functional, OOP, declarative/constraint-based,
concatenative, etc. languages, without having learned a single one." In other
words, someone who was taught to program for the purposes of the test.

~~~
euccastro
How do you learn to program without learning any programming languages?

------
jimbokun
I think that, for those of us who like Lisp, one of the things that draws us
is the elegant simplicity of it all. There are lots of other languages that
distinguish between expressions and statements, function calls and primitive
operations, and all the rest of it.

It is undeniable that there are certain readability advantages to conforming a
little more closely to the conventions from arithmetic notation, or just
looking like C, which is the course most languages take.

But I believe that there are also very different readability advantages to a
very simple, elegant, and consistent notation for representing a computation.
There are fewer things you need to remember and translate in your head to
express the program you want to write, or to understand the program you want
to read.

For the record, I favor the approach Clojure took of making access to the
reader out of bounds for the Clojure programmer, and assigning distinct
semantics to the various paired characters on the keyboard: [] {} (). This
breaks up the visual monotony of traditional S-expressions and improves
readability. But remains simple, elegant, and consistent, in my opinion.

------
ohyes
The parens are a cue so that the editor indents my code properly. How do you
propose to make emacs auto-indent sweet expressions?

It seems that I would have to manually do that as indentation would convey
meaning.

Whitespace is a notorious pain in the ass to get right, parens are visible,
countable, and highlight-able.

Infix is stupidly ambiguous and is the cause of multitudes of errors; a
'natural' way to describe math or not. (There is a reason some prefer the
reverse polish calculator).

Anyway, I don't 'get' the 'aversion' the syntax is trivial to explain and it
keeps me from having to remember fiddly rules. Use a proper editor to
indent/highlight/reformat, and it is as good as any other syntax.

(If you want Lisp to be popular, just get Justin Beiber to write a song about
it).

~~~
cturner
I agree that sexpr are the best syntax out there for a language because it's
consistent and simple. However, this expression thing is a good idea. I've
been waiting for something like this for a while.

    
    
        Anyway, I don't 'get' the 'aversion' the syntax is trivial to explain [etc]
    

Although you mightn't get it, I'm sure you have run into it a bit and realise
it's widespread. Perhaps nine in ten people who identify as programmers would
dislike it. The practice of ignoring that hasn't done any favours for lisp
takeup. It's still a fringe language.

Like the author says,

    
    
        But most software developers have abandoned Lisp precisely because of Lisp's hideous, inadequate notation
    

This syntax is a gateway that allows you to smuggle lisp into a workplace. It
looks like python. When people ask about what you're doing you say "Oh, that's
this cool language called Racket. As you can see, it reads a lot like python,
but I've found it allows me to do xyz nicely. Here, let me show you how this
script works." Then you would show them the script, perhaps show them a repl
tool that appears to work just like python's and they'd be able to get around
your your scripts as much as they can around your existing python code. Sweet!

    
    
        How do you propose to make emacs auto-indent sweet expressions?
    

You could have emacs auto-transform into sexpr when you loaded a file, and
save to sweet expressions when you saved. Should be trivial. From your
perspective, you could like in a sexpr world. Except when you were stepping
your colleague through the code - remember to vi for that bit. Otherwise the
game will be up.

------
ScottBurson
It's a clever design, and Wheeler makes a good case for it. Certainly my first
reaction is "you'll have to pry my parentheses from my cold, dead fingers",
but it's unarguable that a lot of people are repulsed by the syntax, even if
the enlightened among us know it's actually beautiful.

He's right about the requirements for such a syntax: it has to mix well with
the existing syntax, meaning, among other things, it must impose no semantics
and it must not be necessary to write the operands of an infix expression in
infix. I don't recall CGOL etc. getting the latter right. I also agree with
him about the lack of a precedence scheme.

I have to admit, I can see making light use of the curly infix syntax in my
own programs. I'm less sure what I think about the modern-expressions; I'd
have to try them to see. I guess I can see some advantages. But I'm afraid I
draw the line at significant whitespace. I know it works for Python, but
Python was designed for it from the ground up. Looking at Wheeler's example,
I'm not persuaded that it works as well for Lisp, though I commend him for his
effort in designing it.

~~~
ScottBurson
Having the infix expression reader fall back to emitting calls to a user-
provided `nfx' macro seems clever at first glance, but it's insufficient.
Different programs/libraries are likely to likely to implement `nfx' in
different ways, and thus step on each other. I think (for Common Lisp) it will
be necessary to do something like this: create a generic function `translate-
nfx' which uses `eql' dispatching on the first operator, and set up the `nfx'
macro to call it:

    
    
      (defmacro nfx (&rest stuff) (translate-nfx (cadr stuff) stuff))
      (defmethod translate-nfx ((op (eql '+)) stuff) ...)
    

This creates an extensible framework where packages can supply `translate-nfx'
methods for their operations. It would probably be worth predefining methods
for CL arithmetic operations, so that users don't wind up doing that in
incompatible ways. I'm afraid that means choosing a precedence scheme, which
Wheeler was trying to avoid (for good reason); I don't see a way around it,
though.

------
sedachv
I've worked with programs in half a dozen Lisp dialects and everyone who
claims Lisp is hard to understand because of the syntax is wrong. The only
reason I could work with so many dialects and so many programs is because the
syntax is uniform. If you think you have an idea for how to "improve" Lisp
syntax that involves an ambiguous infix grammar, please stop trolling and go
write some Python.

~~~
silentbicycle
Some people seem to have a hard time with deeply nesting languages.
Anecdotally, they seem to prefer "chaining" constructs, like
"someObj.method(arg).otherMethod(arg2).om3(a4).om4(a5)". I'm fine with heavily
nested Lisp-y code, but chaining code feels very awkward to me.

Self and Prolog both have well-designed, completely unambiguous grammars.
People interested in syntax design (or "fixing" Lisp) would do well to look at
those, rather than trying to force a pseudo-Python syntax on Lisp. Python's
grammar has too many edge cases. (Lua's syntax is also quite simple, though
not as much as Self's.)

In the end, clear semantics are at least as important as a good syntax. Lisp
has very clear semantics. So do ML and Erlang, another language which has a
bit of a quirky syntax.

~~~
sedachv
"Anecdotally, they seem to prefer "chaining" constructs, like
"someObj.method(arg).otherMethod(arg2).om3(a4).om4(a5)". "

The thing with fluent interfaces is they're identical to nested Lisp code,
except they read left to right instead of right to left. I suspect writers of
Hebrew and Arabic would find chaining to be more confusing than nested Lisp
code for that reason.

Also worth noting is that a popular style of indenting chained fluent calls is
by splitting them by lines, like:

    
    
      someObj.method(arg)
             .otherMethod(arg2)
             .om3(a4)
             .om4(a5);
    

That's not that different from formatting Lisp code.

------
yason
The new and "readable" syntax looks truly ugly compared to the S-expression
counterparts. Why is it that some people dread parentheses so badly and other
people just never mind and choose to spend the time working with them?

The main reason I consider parentheses and S-expressions superior to other
syntax is that it allows for flexible navigation in the source code. I can
move forward and backward, upward and inward in the tree, unit-by-unit and the
unit can be a literal or a compound S-expression or anything and it just works
the same. (At least in Emacs.)

~~~
gruseom
_Why is it that some people dread parentheses so badly_

Two tendencies combine to make "parentheses" the Lisp topic that in sheer
quantity dwarfs all other Lisp topics added together: 1. the human brain
craves familiarity; 2. people love bike sheds.

(Bike shed = something anybody can have an opinion and argue about
irrespective of knowledge or effort. Since their purpose is to jump into the
argument, these opinions tend to be strong ones, diminishing the likelihood of
any resolution. Indeed, a feature of such discussions is that they are
argument for argument's sake, and thus no resolution is possible or even
desirable.)

~~~
evanrmurphy
> _Two tendencies combine to make "parentheses" the Lisp topic that in sheer
> quantity dwarfs all other Lisp topics added together_

Parentheses (and along with them s-expressions and macros) are one of the few
characteristics still unique to Lisp. Most of the other features - including
GC, dynamic typing, first-class functions and lexical scoping - are now shared
with other programming languages as well.

------
erikb
I am not a big fan of lisp, but u can not really change the lisp syntax and
have lisp anymore. (+ 1 2) has more features included then '1+2', because u
can for example add 3 numbers easily like (+ 1 2 3) and you can treat all that
as a list and parse it to whatever u need, recurse over it and so on. With a
"better" syntax u just don't have these features anymore.

Someone who would use sweet-expressions actually has not understood lisp yet.
But like the mouse mode in Vi, it might be a useful tool to make new lispers
more comfortable. So I still like the idea!

~~~
Kliment
I think you've misunderstood. This does not take away any of those issues.
With this setup, you can write (+ 1 2 3) or +(1 2 3) or (1 + 2 + 3) and they
would all translate into (+ 1 2 3). You can treat any of them as a list. You
can still parse, transform, do anything with it. There is no loss of
functionality here. Think of it as a macro that aliases "plus" to +. There is
no difference between (plus 1 2 3) and (+ 1 2 3) in a macro defined in this
way. They are S-expressions under an invisibility cloak. But they're still
S-expressions within.

~~~
erikb
I understand your point and how this macro works. My point is, that you still
have to think in this (+ 1 2 3) way to be able to write meaningful, recursive,
'code is data' like functions. If u think (func_name param_1 param_2 param_3)
you will easily get a recursive solution for a recursive problem. And if you
think that way anyway, what's the point in writing (1 + 2 + 3) in your code?
It will just confuse the lisp mode in your brain.

I also think it is hard to get into this mode. But like this way of writing is
not basically intuitive, so is recursive thinking and 'code is data' to me
(and so I guess it will be the same for other people). It needs some time of
meditating to get into lisp mode and it also needs some months of training.
But when you are there, everything works together, because it works in the
same way.

Or to say it like Bruce Lee: You must be water my friend. When you fill water
into a bottle, it becomes the bottle. If you fill water in a cup, it becomes
the cup. (And if u put it in braces it becomes a lisp expression: (begin
(water) (q_e_d))).

~~~
Kliment
Well, that does sound subjective. By far not all lisp code is actually being
manipulated as data in any non-trivial way. And for situations where all you
are doing really is adding a few numbers together, why not write it in a way
that is intuitive in the problem domain, rather than intuitive in what you
call lisp mode? To me, being able to separate the two is an advantage. Your
internal martial arts argument is void, for you are frozen in the shape of
s-expressions and refuse to adapt to any other container.

------
agentultra
Isn't Lisp awesome? It's flexible enough that you can write an alternate
syntax, develop your own semantics and grammar, and build the language you
work best in on top of it.

I don't think I've come across another language that can actually do these
sorts of things so well (or at all for that matter).

Viva Lisp!

------
limmeau
I liked the somewhat elegant heuristic for general infix-to-prefix conversion:

<quote> {...} contains an "infix list". If the enclosed infix list has (1) an
odd number of parameters, (2) at least 3 parameters, and (3) all even
parameters are the same symbol, then it is mapped to "(even-parameter odd-
parameters)". Otherwise, it is mapped to "(nfx list)" — you'll need to have a
macro named "nfx" to use it </quote>

That being said, (still-prefer 'I (using 'parentheses :in 'Scheme)).

Now, if someone added mix-fix syntax to Scheme...

------
steveklabnik
Almost like haml for Lisp. Cool.

~~~
nickpinkston
Yea, though you know I'm still attracted to Scheme b/c of its sweet sweet
parens.

------
dish
Is it just me, or does that look like Python?

------
bitwize
"Ugly" s-expressions?

I find them to be quite beautiful, like matryoshka dolls. I am a bit
disappointed when I have to work on code that doesn't manifest its own
structure so explicity, looking like a tangle of words and punctuation down
the page, like what becomes of balls of yarn after a kitten has gotten through
with them.

------
ses
Well from the perspective of a programmer that doesn't know lisp, and has been
put off in the past due to its syntax: I find this dialect much more
appealing.

Nested round brackets are pretty horrible to read / parse.

Whether it destroys the essence of what lisp is all about is another matter,
but I suspect it doesn't at all.

------
Vivtek
Wow. Speaking as somebody who's bounced off Lisp more than once, I find this
really attractive.

------
shaunxcode
once you "get" lisp anything beside s-expressions/prefix notation feels
"inside out" and asymmetrical. I think [ ] and { } should be reserved for
things like dicts, vectors or lambdas.

~~~
silentbicycle
Mostly agreed, but I've used Lisps for years, and prefix for _arithmetic_
still feels weird. My personal preference is infix without operator precedence
(like APL and Smalltalk) or postfix (like Forth). All-prefix, all-postfix, or
all-infix _consistently_ make sense. Infix with arbitrary transposition due to
historical "order of operation" doesn't, but it's the common convention, and
minor changes to it (e.g. +. for floating-point-addition in OCaml) seem to
really piss people off.

Most other function calls are _already_ in prefix notation, people just think
(f x y) is totally weird, while f(x, y) is normal. Cognitive dissonance.

Also, I think it's cute that Prolog sticks all arithmetic under an "is"
operator ("X is Y+Z*3"), rather than letting it dominate the language the way
it usually tends to.

~~~
zephyrfalcon
"Mostly agreed, but I've used Lisps for years, and prefix for arithmetic still
feels weird."

But that is just because you learned the conventional notation from a very
young age, right? We all did, hence the name "conventional". When we learned
to add and subtract, we also learned that the notation was 2+3, not (+ 2 3).
That's why any other notation feels "unnatural".

I do wonder if it would be possible to teach kids prefix notation instead, and
whether such notation would seem completely natural to them. (I suspect the
answer to both is yes.)

~~~
waterhouse
That is an interesting question. I see one possible argument (whose
correctness I don't know enough to judge, I'm just making it up) why infix is
more natural than prefix: A kid will start by seeing an object, and only once
you have an object does it make sense to combine it (by addition or whatever)
with another object. Also, note that a certain amount of English syntax is
infix: "I went to the store", not "Went to I the store".

...However, I think that in some other languages, _postfix_ notation is
common. I think my friend who studies Spanish told me that they say the
equivalent of "I her it gave" (meaning "I gave it to her"), and I think I
remember Shakespearean English using postfix. ...Looking at the text of Romeo
and Juliet, I see both prefix and postfix.

    
    
      Prefix: "O, where is Romeo? saw you him to-day?"
      Postfix: "The which if you with patient ears attend"
    

On the one hand, we could say that, since these plays were apparently rather
successful, people obviously didn't have too much trouble understanding them.
On the other hand, since this sort of strange permutation has been mostly
dropped from common usage (so that I recognize it as strange), that may be
evidence that these things are just harder to use. On the _other_ hand, that
could just be because "common usage" comes mostly from people who have been
educated in schools, and schools have no reason to teach more than one method
of speaking. On the _other_ hand, Shakespeare seems only to have done that in
order to make lines fit into rhyming iambic pentameter; in no way was this
natural to him.

I should probably note that a lot of speech deals with object method calls
more than function calls ("I.saw(Bob.win(a_game))" or, as it would probably be
expressed in Arc, "(I!saw (Bob!win a-game))"; function call would be like (saw
I (win Bob a-game))). And adjectives and adverbs act kind of like keyword
arguments: (I!drove :to (the store) :[qualifier] fast). From that perspective,
the distinction might be "object method calls" vs "function calls", rather
than "infix" vs "prefix".

Does someone who knows more than I about other human languages (or English,
for that matter) know about the prevalence of postfix notation (and prefix, if
it so happens)?

~~~
silentbicycle
Turkish and Japanese both typically end sentences with verbs, IIRC. There are
probably several others; I really should just buy a copy of Comrie's _The
World's Major Languages_ already.

In German (which I'm at least a little familiar with, unlike those two),
auxiliary verbs stack at the end of the sentence: "I have eaten my breakfast."
-> "Ich habe mein Frühstück gegessen." (lit. "I have my breakfast eaten.")
It's unusual to have more than a couple, though - human languages typically
don't nest very deeply.

OTOH, comparing natural languages and programming languages may not be that
useful - programming language design places a high priority on avoiding
ambiguity, while natural languages assume have quite a bit of it. It may be
better to consider programming languages as a kind of notation for math,
logic, rules, instructions, declarations, etc. Kenneth Iverson had some
interesting ideas about that.

Another issue with method calls is that many things don't have a clear primary
actor. In single-dispatch OOP languages, this turns into ugly workarounds
(e.g. the Visitor pattern), "who owns this method?" debates, and tedious
rewriting. Multimethods avoid that issue entirely.

------
evanrmurphy
Update: The page at <http://www.dwheeler.com/readable/> appears to be the
project's homepage.

------
woid
Sweet-expressions is for LISP as CoffeeScript is to Javascript :-)

~~~
evanrmurphy
This touches on the core of my enthusiasm about sweet-expressions. I'd like to
make a "SweetScript" that compiles to JavaScript (via some lightweight lisp)
and could essentially serve as a CoffeeScript with macros.

Would you find such a tool useful? What challenges would you foresee facing
such a project?

------
jpr
It's funny that Lisp's "syntax" draws so much attention when it is pretty much
the simplest and most unambiguous syntax possible, and that messes like C++,
Python and Perl don't seem to bother anyone enough to propose alternatives.

~~~
silentbicycle
It's yet another case of people getting hung up on the first obviously
different thing they notice about a language.

If somebody is still griping about the parens in Lisp, the significant
whitespace in Python, the glyphs in APL, etc., they haven't gotten to the
differences that actually make the language interesting - either they'll get
used to it like the other X programmers (and realize it wasn't as big an issue
as they thought), or they'll find deeper issues in the language design to
complain about (and probably give up on it).

