def foo (a b c)
spam a
eggs b
ham c
Creates the following expression: (def foo (a b c)
(spam a
(eggs b
(ham c))))
Where every new level of indentation is interpreted as a new expression.Unfortunately, seeing as I am more familiar with Common Lisp than Scheme, I wrote in CL, so you can't actually try the new syntax in Arc (yet). And my code is probably pretty buggy, as I just wrote it in a couple of hours. But for what it is worth, you can get my code and try it out in your favorite CL implementation:
http://blackthorncentral.net/files/read-indentation.lisp
There are some thoughts here[1], though I don't like how he's moved the procedure outside the parens to match algol-like languages and I don't like the curly braces stuff either.
-----
"I spent a couple days working on getting rid of parentheses, and it got really ugly." -- http://news.ycombinator.com/item?id=35795
-----
This seems such an obvious idea, either it is actually hopelessly flawed, or else it has already been implemented by someone somewhere.
-----
-----
(Note: if you actually want to try this, in addition to just adding (require "read-indentation.scm") and changing various instances of (read) to (read-indentation), you probably want to add (flush-output) after the (display "arc>") in the toplevel definition, or the REPL you'll get will be extremely messed up.)
-----
-----
Anyways, I don't particularly see that as a reason not to try the syntax at all.
In particular, I don't see how this syntax would be a Bad Thing. I mean, Python uses such a syntax, and so do other languages. And Python hasn't gone down the tubes because of its use of an indentation based syntax. So why can't a Lisp use such a syntax? The conversion between normal S-expressions and indented expressions (or I-expressions to use the SRFI term) is fairly straight forward, the code looks almost exactly the same minus the parentheses, and you can even interface with the traditional reader such that expressions of the typical (...) form read in normally (this is in fact what my code does). In short I don't see a significant difference between Python and Lisp that allows Python to use the indentation and not Lisp, except possibly that Python has to define an entire syntax to accomplish this and Lisp only requires a single function to be defined.
I'm not claiming that my code will amount to anything (I would be very surprised if it did), but I am saying we shouldn't dismiss the indentation based syntax out of hand.
-----
if ---> (if
test ---> (test)
exp ---> (exp)
test2 ---> (test2)
exp2 ---> (exp2))
Not that doing so makes it much better, because you still can't indent the expressions beyond the tests (and you can't indent the final default case either). On the other hand, if you kept the parentheses, because starting a line with a list turns off the conversion in my current system, you could do a more traditional style: if
(test) (exp)
(test2) (exp2)
Which would get converted to the same thing. But that isn't really satisfactory for longer if statements, with tests and expressions that take a full line each, and with enough cases that different indentation for test and expressions is needed to make the thing readable. So the syntax would probably need some significant revisions before it would be actually usable in code of any significant size.-----
(if x
m
y
n)
BTW a bunch of people (mostly started by David Wheeler) have been discussion such syntaxes. See:https://lists.sourceforge.net/lists/listinfo/readable-discus...
-----
But I think I know what you are really getting at, because when the single letter symbols above are more complex expressions, converting the above gets much more difficult. The fact is, in a system where indentation is significant, you can't make arbitrary decisions about indentation to make the code look the way you want. So either you have to line everything up equally so you can't distinguish between test and expression, or you need to come up with some fancy indenting rules that somehow know what an if expression is supposed to look like. I don't particularly like the former, and I'm to lazy to really work on the latter, so that leaves us with just having the badly formatted if expressions. (Unless someone else can think of something. Maybe that discussion does, but I don't entirely have time to look through their archives right now.)
But at the very least I am having fun messing with Arc internals, so not all is lost.
-----
if ---> (if
test ---> (test)
exp ---> (exp)
test2 ---> (test2)
exp2 ---> (exp2))
So, what if I need the variable test, not the function test? Suppose instead I have something like this: (if
test
(exp
(exp2
(very-long-exp3 5 6 7 8))
(some-random-exp4))
test2
(exp5
(exp6)
(exp7)))
If a naked symbol all by itself becomes (symbol), how do I format the syntax if I need symbol, not (symbol)?-----
I can't see any way to make indentation show you need just a symbol and not a function call with no arguments. You could add symbols, but that works against the removal of the parentheses in the first place.
Its a bit of a hack but if you had a simple read macro for an identity function you could do it. (Quote doesn't quite work because it prevents evaluation.) But say you had a function identity like such:
(def identity (x) x)
And you defined a CL style read macro (e.g. $) to expand to (identity x). Then in my current function, because the read macro would expand before checking the subexpression to see if it was a list or not, you could do the following: if
$test
exp
exp2
very-long-exp3 5 6 7 8
some-random-exp4
$test2
exp5
exp6
exp7
Which basically exchanges all the parentheses in the traditional version for a identity macro. Of course, it isn't exactly the same because you are adding extra meaning (the call to identity) to the expression. But maybe you could make it a macro instead of a function, and do the expansion at compile time (although this is dangerous because if you expanded the macro too soon you would defeat the purpose of using it in the first place...): (mac identity (x) x)
On the other hand you could alway just use traditional s-expressions in the middle of significant-indent code. The goal is to make parentheses optional, not to remove them entirely. Sometimes it may just be more convenient to leave them in than take them out.-----
If you consider that the reason we know to add parentheses around structures in the first place is the indentation of forms below the current line, then it is ambiguous whether a form with no nested forms should be wrapped in parentheses or not. If the system then does not assume the innermost forms are function calls, then it solves the problem of interpreting literals as function calls. Thus you can now do this:
if
test
exp
exp2
(very-long-exp3 5 6 7 8)
(some-random-exp4)
test2
exp5
(exp6)
(exp7)
Which cleans up many parentheses (removing all parentheses was never our goal in the first place), and doesn't result in the extra parentheses that were a problem before.I found that it was trivial to implement this in my previous code. You can find the updated version at: http://blackthorncentral.net/files/read-indentation.scm
-----