There've been so many attempts at removing the parentheses from Lisp, to make it look more like C/C++/Java, or (more recently) Python, or other.
FWIW, there've been many attempts in Scheme (and Racket), including one by the core Racket developers (Honu [1]), but they've never taken off. New people decide to use parentheses.
There's a phenomenon with Lisps, in which, speaking loosely, half the people who first see a Lisp think the parentheses are a problem, and immediately start to propose "solutions" for "acceptance". But then they try the Lisp with the parentheses, in an editor with at least simple indenting support, and they very quickly get used to it, and maybe even value it. (A small percentage of them will still put each close-paren on its own line, for a substantially longer period, but it seems even most of them will quickly learn to snuggle close-parens and possibly to use fancier editor commands for movement and editing based on expressions rather than lines.)
Programmers seem more malleable than we might think. I'm not as sure about those mathematicians or scientists who try to minimize their time learning programming, or who are necessarily working with hairy expressions in LaTeX and don't want to have to keep translating. For possible use of those people, there are a number of efforts to permit expressions to be in more familiar infix order [2], and to support familiar TeX math notation in the Racket-based typesetting/documentation system [3]. (And if you don't like those, Racket will let programmers plug in your own reader or `#lang` to make another attempt at this atop Scheme.)
> There've been so many attempts at removing the parentheses from Lisp
The best previous attempt IMO was Egil Möller's I-expressions in 2003 (https://srfi.schemers.org/srfi-49/srfi-49.html). These Sweet-Expressions in the OP I think were a regression on I-Expressions.
My attempt (~2013-present) is called Tree Notation. http://treenotation.org/. This is the first time that we've got S-Expressions without parentheses and are using that for tremendous benefit (better concatenation, easy ad hoc parsers, visual programming and program synthesis being some of the main benefits).
It's going to happen finally with Tree Notation. We're starting to see strong network effects at last. The missing ingredient was strong tooling/design/and tools that leverage the lack of parentheses to huge benefit.
> OP claims to be backwards compatible with Clisp, that's not a goal of yours, right?
Correct, not a goal of mine. If someone wanted to create a Tree Language that compiles to CLisp, they could define it in our Grammar Language (http://treenotation.org/sandbox/build/ -- you write your grammar on the left, and source code in your new language on the right).
> So a list in treenotation would be written:
list a
1
2
3
4
The base spec for Tree Notation is very simple.
YI = "\n" // New lines separate nodes
XI = " " // Increasing indent to denote parent/child relationship
interface TreeNode {
parent: &TreeNode
children: TreeNode[]
line: string
}
In practice, we generally break "line" into "words: string[]". So you can represent atoms in a list as either words or nodes, depending on how you design your Tree Language.
> Could become a bit verbose at times, or does treenotation have a mechanism for tables like
Sort of. We have a software coming out called TreeBase that is a plain text, git backed database that stores records in Tree Notation. In there we have Tree Languages for dealing with SSV/TSV/CSV/etc tables. I'm not 100% happy with the current implementation--going to be putting pattern matching into our Tree Grammar Language which might solve it--but I bet within a month or two we'll have a great solution for that with strong type checking, etc.
> Does treenotation differentiate between strings and data/ints?
The base Tree notation is very simple, as the spec above shows. But we created a Tree Language, built upon Tree Notation, wherein you write grammars to create new languages. In those grammar files you can define ints, strings, arrays, etc. The link above has examples with all of those.
It's a neat idea, and pareinfer just looks beautiful, but why even infer them at all if you don't need them?
My long term plan is to get a lot of resources dedicated to this initiative, and even though I think it's possible you could accomplish the same thing with S-Expressions, I think it's simpler and cheaper by a significant amount to just drop the parens.
I think the number of folks who are comfortable with parens (I'd count myself in that category) is a lot smaller than the folks who don't like parens or don't have a preference.
I think the advantage is backwards compatibility. I use pareinfer with Clojure and Emacs Lisp for example, though generally I'm more a fan of paredit.
I did think of making an Emacs plugin that could hide the parens when using pareinfer. They'd still be in the code, say for others who choose to use a different editing style, but hidden to me.
Another aspect for Lisps is that single line code blocks at the REPL are quite useful. Not all shell have good support for multi-line, so being able to inline tree like code does come in handy there.
I've also personally found the parens sometimes help with readability, indent can be hard to tell where the block starts and ends sometimes in deep nested scenarios which is more common in immutable expression only languages.
Lastly, I'd say copy/pasting can be annoying in whitespace sensitive syntaxes. Pareinfer suffer from this issue as well.
But I'm biased, I like the parens and love S-expressions. I'm one of those who started like everyone else hating them, trying to look for alternatives, but one month later of using Clojure at work it all changed, my brain adapted and now I find S-expressions superior in all ways to all other syntaxes I've ever used. I even find myself writing other language with S-expressions by accident. I often put the parenthesis before the method by accident now when going back to Java for example.
> Another aspect for Lisps is that single line code blocks at the REPL are quite useful. Not all shell have good support for multi-line, so being able to inline tree like code does come in handy there.
This is a really good point. I'm thinking of experimenting with a convention for doing inline trees using Tree Notation. In the code itself the delimiters are called YI (newline) and XI/ZI (space), so potentially could do something like this for the REPL: (set YI="|" ... "def square x|return|* x x "
> Lastly, I'd say copy/pasting can be annoying in whitespace sensitive syntaxes.
This is true. Things that minimize it in Tree Notation: no ambiguity with spaces/tabs/indent levels--one space is the only way to indent things; great syntax highlighters & automatic suggested fixes (I've got a todo to add autosuggested fix the common case where subsequent lines are de-dented after a paste); and the ubiquity of multi/vertical cursors in editors nowadays. Still, whether I'm using Sublime or VS Code or vim, indent can sometimes be an issue. I think it's just a matter of having all the grunt work done for the modes in these languages to ensure things work as you'd expect. I bet we get that all done by end of year at latest.
> my brain adapted and now I find S-expressions superior in all ways to all other syntaxes I've ever used.
I think largely the same way, except to me just swap S-Expressions with Tree Notation (which is just SE w/o parens). But that's only because the tooling is getting there now. When I look back at where things were in 2017, wow, Tree Notation was very hard to use back then.
>> There've been so many attempts at removing the parentheses from Lisp, to make it look more like C...
I think it's less about looking like C (or other) it's about looking like normal Math: (f 1) vs f(1). The above plugin solves this. Maybe the neoteric feature is the most important of the three extensions.
But then again `unnecessary` braces are nothing to torture malleable newcomers with, they are just a thing to get rid of.
There've been so many attempts, of various stated motivations. Many of them have been expressly to make it more familiar to programmers (not mathematicians). Which, for all of the time I've been in Lisps, has meant the series of languages that mimicked the syntax of the language before, for the same familiarity/acceptance reason: C, then C++, then Java, then JavaScript. There's also been the indentation-sensitive ones that are influenced by Python. And the math ones.
You're ignoring the vastly larger group of developers, of which I am one, that simply refuses to program in lisp specifically because of the parenthesis hell.
Lisp, as McCarthy proposed it in 1958, actually had an alternate syntax called M-expressions that would be perfectly readable to any JavaScript programmer: (foo a b) became foo[a,b].
It never took off. From the earliest days -- before video terminals were a thing, let alone video-terminal editors that could match parens and indent automatically -- people just preferred working with sexprs. I think it has to do with the fact that while mexprs are easier to read with prior ALGOL experience, sexprs are easier to transform, and to reason about their transformation.
I think Lisp is one of those things where, you either get it or you don't, and once you do get it parens are a non-issue. There's a fundamental leap of insight that requires enormous activation energy to achieve.
Never took off? In addition to the other replies, look at Mathematica/Wolfram Language where they are _the_ syntax:
f[1, 2, 3]
And we can index it
Part[f[1, 2, 3], 1] == 1
Now what would the 0th element be?
Part[f[1, 2, 3], 0] == f
It is “head” or what corresponds to the first element in cons lists.
Also, as an appendix, there is no reason why you can’t have a “high-level” syntax and an abstract syntax which can both coexist. Mathematica has a syntax which can get quite cryptic (almost APL like at times), but it is possible to ask “freeze” expressions and print out the full m-expression form and thus inspect the structure of a function or similar.
Yeah it's possible, but it leads to somewhat awkward languages where you have sometimes multiple levels of desugaring going on and it's annoying. The last time I looked into Julia (IIRC >6 years ago) it had something similar going on and it really scared me off. The problem with having a "technically homoiconic" language is that you're going to end up with not only lots of desugaring, but multiple syntaxes for the same things.
The idea of the m-expressions might be coming back though, two of the popular newcomers are homoiconic languages (depending on your definition), Elixir as a functional programming language and Julia as an imperative CLOS inspired language.
Being not as powerful (able to create any valid syntax due to more complex and rigid parsing rules) and trivial to manipulate code as data as s-expression is considered a feature, as it helps preventing the proliferation of language extensions while still allowing them when their benefits outweighs the costs. Even the main elixir metaprogramming book starts with saying: "the first rule of macros: don't use macros", and in Julia you have to attach a @ to call a macro to make it clear that the normal rules of the language do not apply ahead. Those languages also focus in providing everything the user needs without the use of macros, which are for more advanced purposes.
While people who use Lisp eventually see the advantages of s-expressions (or at least of writing more idiomatic code in those languages), being attractive to new users coming from the more popular languages is very important (and like clojure interoperate with java, it might be even easier to make a lisp that has perfect interoperability with Elixir for example, so both groups can coexist).
Re: "trivial to manipulate code as data as s-expression is considered a feature"
Although Julia goes further in other directions, just changing the surface syntax of s-expressions, like this proposal, doesn't really interfere with this feature. With alternate syntax, you can still write macros and stick to the code-as-data idea in pretty much the same way. In Lisps with a programmable reader (like Common Lisp and some Schemes), you can set up the reader to recognize something like foo[bar,baz] as an sexp, and once read, it'll be represented internally exactly as if (foo bar baz) had been read with the default reader. Then any macros and even code-walking code continue to work the same as before.
I meant that macros being a little harder to use and the result being a little more restricted is the feature, a small protection against the Lisp Curse (if every custom language is just as good as the base language, then no one can agree what the base language should be). Kinda like newer languages kinda avoid inheritance because while it's powerful, it's kinda easy to misuse (though Elixir special 'using' macro is a fantastic simple way to share behavior between modules).
And while programmable reader macros allow Lisp to have any syntax you want, they go even further in producing heterogeneous environments in which not even the parsing rules are shared. But you can't just only know the algol/infix way of programming in Lisp since you'll have to see other people code and documentation, and when you use these alternate parsers/extensions other people have to understand the quirks of your unique parser/extension before understanding your code. Everyone using the exact same language is definitely a feature, and those languages (and clojure who dropped programmable reader macros and asks people to use macros more judiciously) have a point in their belief.
But as a curiosity, Julia also has it's own version of reader macros [1], which can be used to give it s-expression syntax [2].
You're probably right, I didn't really go deep in with the macros, mostly just injecting code with 'quote' to remove occasional boilerplate. The point was more about the ability to easily manipulate the code within the code to create DSLs (like Ecto for SQL) in a "lispy" way, which Elixir is notably good at. In that sense we can add D, Rust and Nim as well, all somewhat recent languages that also provide that feature.
Yeah I had just read some stuff about Elixir not being homoiconic and wanted to just point that out (in essence, I was being pedantic), it doesn't really ding your point.
> "There's a fundamental leap of insight that requires enormous activation energy to achieve."
I don't think it requires energy per se, because s-expressions aren't actually difficult at all. The biggest hurdle seems to be willingness to learn something new.
That's actually a very good point. From my anecdotal experience, I actually vastly prefer Lisp like syntax to basically any other syntax because it's so regular and clearly delimited, so I can grab whole expressions and move them around and transform them really easily. It also makes it easier to navigate code, and in my opinion easier to read since I don't have to remember "syntax", just the behavior of functions and macros.
Weirdly enough, even if a language isn't "lispy" I would still consider a expressions a point in it's favor.
Frankly Ill take the extra visual structure of square brackets and commas for lists instead of overloaded parens and white spaces of Lispy sexprs any day.
There's a line in The Matrix where Neo asks Cypher why he looks at the raw green code of the Matrix. He replies "You have to...and all I see is blonde, brunette, redhead" (or something to that effect).
Every time somebody proposes to "fix" Lisp's syntax it reminds me of that scene. It sounds like a newbie Lisp programmer who hasn't yet experienced the thrill of seeing beyond the parentheses. And the mind-boggling compositional utility that comes from leaving them alone.
The point is: Most of the parentheses are superfluous and removing them (in the right way) takes nothing away from the mind-boggling compositional utility.
There is no need to remove them. They are disturbing only people who don't program with Lisp a lot. It's possible to make Emacs to almost hide the parentheses using very low contrasts for "(" and ")" but even that is mostly useless once you are used to them.
I parse Lisp similar ways and speed as Python. The indentation in Lisp code is works the the same way.
Q: How can you tell when you've reached Lisp Enlightenment?
"The parentheses disappear." Exactly so. But, you have to use a proper editor with automatic indent, paren matching, and the ability to navigate by s-expressions. Composing lisp with something like Notepad is just a waste of time and an exercise in frustration.
It is the unambiguous notation enabled by the parentheses that allow lisp to process code as data and construct programs on the fly.
IMHO, those who suggest eliminating the parentheses don't yet understand lisp. Trying to make lisp more widely acceptable by eliminating them is throwing the baby out with the bathwater.
> What's wrong with the three equivalence transformations of OP?
Objectively:
1. I can't look at a line and tell if I have a complete expression. I must look at the following line and compare its indention level to this line. I may also need to look at the previous line(s) to see if we've switched to infix unexpectedly.
2. Indention means your programs will be bigger in physical area (meaning more scrolling).
Pragmatically:
3. People are unable to reliably copy/paste indention-languages into many web forums (like HN and Reddit) making it harder for them to get the help they need when starting out.
4. It's slower and more complex to parse, making build/compile times slower.
It seems a lot more complicated. You have to parse the type of bracket used, you have to move your eyes across lines to understand nesting. I don't know. I find the Lisp way on the right side way more readable, but I'm an active Clojure developer so maybe there's that.
> Exactly so. But, you have to use a proper editor with automatic indent, paren matching, and the ability to navigate by s-expressions.
Autoindent and paren matching is currently a basic feature of virtually all mainstream text editors. Therefore, picking up any random mainstream text editor is already enough to address your concerns.
I don't think "notepad.exe is a shitty editor for this language" is a relevant objection in the first place. It's like criticizing python because notepad.exe lacks an auto-indent function.
They are disturbing only people who don't program with Lisp a lot.
Which is about 99.9% of the population. It's good for Lispers that they can ignore braces, but why ignore them when you can just drop them (in many cases), and thereby increase it's chance of mass adaptation.
There is Ruby and it's popular. Apple did it with Dylan in 1992, it didn't become popular.
There is no need to change Lisp into different language because they already exist. Trying to get people who don't want to learn Lisp to learn Lisp is pointless.
Agreed! For decades some people have said parens in S-Expressions are useless.
But a key thing we're pushing, that's never been pushed before, is that the parens are worse than useless--they are harmful! They prevent easier program concatenation and ad hoc parser writing. And they make program synthesis, visual programming, and code analysis ~10x harder, for next to no gain.
I'm hoping we'll start to turn the tide and bring the 99.9% of the population into the Tree Notation world, and those LISPers that love their parens can remain happily in their (world).
> But a key thing we're pushing, that's never been pushed before, is that the parens are worse than useless--they are harmful! They prevent easier program concatenation and ad hoc parser writing. And they make program synthesis, visual programming, and code analysis ~10x harder, for next to no gain.
Almost everything you've said above is not just untrue, but the opposite of the truth. As such, your statements require supporting evidence. Please cite some.
There is a lot of evidence in the GitHub. See JTree library and the ohayo data vis tool.
There is also a big open source release coming soon—the largest database of programming languages and features in the world by a factor of at least 10x, more like 100x. Over 10k languages, over 1k columns.
We is the Tree Notation Lab. Will be announcing what that is and the funding for it later this month.
> They prevent easier program concatenation and ad hoc parser writing.
This assertion is patently false. Parens make it quite trivial to parse and render the underlying tree structuee rather obvious. Concatenating programs is just a matter of splicing a subtree into the target tree.
- In S-Expressions with parens, there are infinite ways to write any given abstract syntax tree.
- In Tree Notation, there is only 1 way to write any given abstract syntax tree.
If you change one letter, you get a different tree.
- Say I wrote programs in a Tree Language with a root node called "dumpToConsole" and I want to
rename all such nodes to "print". I can write a type-safe ad hoc parser that does
a simple search replace "/\ndumpToConsole/print/",
using Tree Notation. If it were in S-Expressions, I'd have to use a full parser.
Parens are anything but superfluous. Substituting whitespace for parens is a net loss IMO because indentation errors become semantic rather than merely unaesthetic. And elegant composition is impossible with infix notation unless -- you add parens again.
> Substituting whitespace for parens is a net loss IMO because indentation errors become semantic rather than merely unaesthetic.
With good tooling this is not a problem. Try the demos here: http://treenotation.org/sandbox/build/. Make some indentation errors. It's very hard to ignore all the help the editor gives you.
> And elegant composition is impossible with infix notation unless -- you add parens again.
This is a valid criticism. I've seen some folks working on this though, and I expect we'll see a new elegant solution.
Assigning priorities/precedence rules to operators is a problem. It's a hack to work around the paren-less infix notation not being able to fully describe a tree. It introduces complexity in parsing and it imposes mental overhead on programmers.
You'll note that most code people write in almost any language is prefix anyway. `foo(bar, baz)` isn't infix; it's prefix with the operator placed to the left of the paren.
FWIW, I think Haskell does an excellent job of facilitating composition without parentheses, and thus I'm going to contradict what I said earlier about parens always being necessary. But Haskell also does automatic currying, which even Lisp doesn't do. Without automatic currying, I'm pretty sure my original point still stands.
You are possibly right about indentation errors, but the way I understood it, the Readable plugin does not take away any compositional powers. It's just equivalences:
There was a vertical-tab run in ‘13 that really hurt a lot of us; other than that, the Central Space Bank (at least in the US) has kept things fairly stable. (This is ignoring the doom-and-gloom quantitative-tab-easing conspiracy theory nuts.)
Indentation is an occasional minor annoyance when copy pasting, but otherwise mostly solved by IDEs. In any case very acceptable given the much increased readability and esthetics. I'm not sure if semantic bugs from mixing tabs and spaces are even possible with modern python parsers.
if 1:
<tab>if 0:
<tab><tab>print(1)
<spaces*n>print(2)
could print 2 if mixing tabs and spaces were allowed. was it ever?
How about the opposite direction? Instead of needing parentheses in a language with infix notation, can parentheses be removed in a language with prefix notation (like Lisp)?
Is elegant composition possible with prefix notation and some whitespace and indentation instead of parentheses everywhere?
I would hate to try to write a macro for "sweet expressions". The parens show the structure, and the whole point of representing programs as their own literal structure is that it's easy to manipulate.
Without that, why am I using Lisp? If I just want a reasonably high-level language but don't care about macros (or other features that rely on seeing the actual structure clearly), why wouldn't I just use Ruby/Python/Smalltalk? They're pretty good, too.
I can almost guarantee it's going to be more pleasant, down the road, using one of those languages as it's intended to be used, rather than trying to contort Lisp this way. Getting an answer to a Lisp question on StackOverflow is hard enough with standard syntax. No Lisp programmer is going to want to help with a program written like this.
There might be situations like macros where the classical notation is easier to read and understand. Sweet expressions are an optional extension of the language so you can just use them in ‘normal' situations
I've made clojure my main language late last year and while reading lisp code seemed alien at first, I've now adapted and have no trouble reading s-expressions.
And once you truly understand that `(map inc [1 2 3 4])` is just a list, things like macros begin to click and you understand the power that is given to you.
In fact, I'm missing an equivalent to paredit now when I have to go back and code Java/JavaScript :)
If you know Lisp you will instinctively convert any syntax back to S-expressions anyway because that's how things will eventually work anyway and because you can't think of Lisp macros otherwise. So, the syntax becomes a burden, and thus you settle for the minimalist, easiest way to denote trees.
Lots of talk about removing the parenthesis, using things like Tree-Notation and such.
Really, all I can say is that you can pry the parens from my cold, dead, cantankerous hands. :P
Maybe it's because I've been playing with Lisp, in one form or another, on and off for several years.
But I never found the parens really all that bad.
It's no problem at all as long as you have basic paren matching support in whatever editor you use.
And if you happen to use an editor that supports the structured manipulation of S-expressions, well, it's a pretty neat experience.
I think the only time the parens bother me is if I print source code out. But even then, there are clear conventions on how Lisp source should be laid out and indented, so you adapt pretty quick, even in the "worst case."
> Such hyperbole can only be found in the lisp world.
Paul Graham may agree with you! Graham found a guy on slashdot with the same funny notion:
> "I have heard more than one LISP advocate state such subjective comments as, "LISP is the most powerful and elegant programming language in the world" and expect such comments to be taken as objective truth. I have never heard a Java, C++, C, Perl, or Python advocate make the same claim about their own language of choice."
> - A guy on Slashdot. What theory fits this data?
The submitted title was "readable lisp with infix and less ((braces))". That was not the original. The original title is "Readable Lisp S-expressions Project", so a moderator changed it to that, in accordance with this site guideline: "Please use the original title, unless it is misleading or linkbait."
On HN, being the submitter of an article conveys no special rights over the content, such as how to frame it for readers. If you want to express your opinion, the place for that is in a comment; then your view is the same level as other users'. Titles are by far the biggest influence on threads, so this rule is a big deal.
The parentheses in Lisp are like the white-space in Python - something non-users often get hung-up about when looking at the language, but which turns out to be a non-issue when using the language for a short while.
A more conventional syntax might look more appealing for non-Lispers, but I don't think it will make a big difference for adoption. If you want a more conventional-looking language, there are already plenty to choose from.
XML has attributes which S-exprs don't. This can be solved by convention (as SXML does) and doesn't really represent a difference in expressibility.
S-exprs have quote and unquote which XML doesn't. This is a fundamental difference and makes it hard to convert Lisp code that mixes code and data representations.
FWIW, there've been many attempts in Scheme (and Racket), including one by the core Racket developers (Honu [1]), but they've never taken off. New people decide to use parentheses.
There's a phenomenon with Lisps, in which, speaking loosely, half the people who first see a Lisp think the parentheses are a problem, and immediately start to propose "solutions" for "acceptance". But then they try the Lisp with the parentheses, in an editor with at least simple indenting support, and they very quickly get used to it, and maybe even value it. (A small percentage of them will still put each close-paren on its own line, for a substantially longer period, but it seems even most of them will quickly learn to snuggle close-parens and possibly to use fancier editor commands for movement and editing based on expressions rather than lines.)
Programmers seem more malleable than we might think. I'm not as sure about those mathematicians or scientists who try to minimize their time learning programming, or who are necessarily working with hairy expressions in LaTeX and don't want to have to keep translating. For possible use of those people, there are a number of efforts to permit expressions to be in more familiar infix order [2], and to support familiar TeX math notation in the Racket-based typesetting/documentation system [3]. (And if you don't like those, Racket will let programmers plug in your own reader or `#lang` to make another attempt at this atop Scheme.)
[1] https://docs.racket-lang.org/honu/Examples.html
[2] https://docs.racket-lang.org/guide/hash-reader.html#(part._r...
[3] https://docs.racket-lang.org/scribble-math/index.html