I wrote a racket function that would need 35 levels of indentation ten minutes ago. White space isn't coming for lisps until we figure out 12 dimensional displays.
Wisp [0] is the big one talked about in Scheme land, and it wouldn't need 35 levels of indentation. Like the rest of Lisp-world, there's flexibility where you need it.
For example, this shows a bit of the mix available:
for-each
λ : task
if : and (equal? task "help") (not (null? (delete "help" tasks)))
map
λ : x
help #f #f x
delete "help" tasks
run-task task
. tasks
An everyday example is the difference between JSON.stringify(data, null, 2) and a pretty printer like ipython or Deno.inspect. Having only one node per line reduces the amount of data that can be displayed. It's the same with code.
Recursive teXt (RX) would be a great fit for Lisp, although I am more interested in replacing Lisp entirely with a simpler language rooted in abstraction logic.
Note that RX is not like normal semantic white space, but simpler. It is hard coded into the text without taking its content into consideration. RX is basically nested records of text, making it very robust, but encoded as plain text instead of JSON or something like that.
> S-expressions are the simplest way to linearize a tree.
S-expressions are one way to linearize a tree.
Now, "simple" can mean different things depending on what you are trying to achieve. RX is simpler than s-expressions if you prefer indentation over brackets, and like the robustness that it brings. Abstraction algebra terms are simpler than s-expressions if you want to actually reason about and with them.
In your own examples you're using both brackets and white space to delineate structure. This is complex because you need two parsers to even start working on the input stream and the full parser must know how to switch between them.
In short: I get all the pain of semantic white space with all the pain of lisp s-exp's with the benefits of neither.
In my examples I use RX for the outer structure, which is unproblematic, as
RX itself is not complex at all, and parsing it is easy, as easy as parsing brackets.
What kind of content you put into the blocks, depends on you. How you parse one block is independent from how you parse another block, which means embedding DSLs and so on is painless. You could view the content of a block as RX, but you can also just see it as plain text that you can parse however you choose.
This also means if you make a syntax error in one block, that does not affect any other sibling block.
The benefits of RX, especially at the outer level, is that all those ugly brackets go away, and all you are left with is clear and pleasing structure. This is especially nice for beginners, but I am programming for over 30 years now, and I like it also much better.
If you don't allow the indentation based parsing to be nested within a bracket-based expression, it doesn't look too bad. At the top level you have the indentation-based parser. When that sees an open bracket, it recurses to the regular parser which doesn't care about indentation.
I'm reasonably sure you could conceal this surface syntax so that macros don't know it exists and work fine. You can call a macro by writing the invocation syntax using the indented format, or by the bracketed format, or a mixture.
It's been done before; see Scheme SRFI-110, a.k.a. Sweet Expressions or t-expressions:
Yes, for a general language (such as abstraction algebra) you would want to allow mixing normal term language and blocks. In RX, that is easy to do: Just reuse the blocks that RX already gives you, while the lines of a block are there for the term language.
Assuming this number of indentation is really necessary (which I doubt; maybe a few auxiliary definitions are in order?), obviously only the first few levels would be represented as their own Recursive teXt blocks.
It is obvious to me, nobody would want to represent 35 levels of nesting by indentation. So I would represent the first few (2-4) levels in RX, and the rest
by other means, such as brackets. Your language should be designed such that the cutoff is up to you, the writer of the code, and really just a matter of syntax, not semantics.
Obviously, I (usually) would not want to write things like
+
*
a
b
*
c
d
but rather
+
a * b
c * d
or, even better of course,
(a * b) + (c * d)
I think of blocks more as representing high-level structure, while brackets are there for low-level and fine-grained structure. As the border between these can be fluid, where you choose the cutoff will depend on the situation and also be fluid.
> I have more important things to think about in my code than when I switch between two dialects of the language.
Granted. The example I gave was just to demonstrate that switching between the styles is not a problem and can be fluid, if you need it to be.
> It's only fluid because you've had XX years of infix notation caused brain damage to make you think that.
No, infix is just easier to read and understand, it matches up better with the hardware in our brains for language. If that is different for you, well ... you mentioned brain damage first.