Traditional S-expressions, by their definition, ignore most of whitespace; additionally, reading sexprs is always a linear operation without the need to backtrack by more than one character.
The suggestion from this post violates both assumptions by introducing a 2D structure to code. To quote this post's examples, it requires the multiline string in
(fst-atom """ trd-atom)
00001
00002
00003
"""
to be fully read before TRD-ATOM. It also forces the reading function to jump up and down vertically in order to read the structure in * ( )
* e ( ) ( )
* q m ( ) p ( ) *
u a a o a 2 *
l w *
The author also states that (eq (mul (a a)) (pow (a 2)))
is less readable than * ( )
* *eq* ( ) ( )
* *mul* ( ) *pow* ( ) *
*a* *a* *a* *2* *
*
Then there's the ending passage:> we hope that the introduced complexity is justified by the data readability expressed this way.
I cannot force myself to read this post as anything but a very poor Befungesque joke.
#lang 2d racket
(require 2d/match)
(define (subtype? a b)
#2dmatch
╔══════════╦══════════╦═══════╦══════════╗
║ a b ║ 'Integer ║ 'Real ║ 'Complex ║
╠══════════╬══════════╩═══════╩══════════╣
║ 'Integer ║ #t ║
╠══════════╬══════════╗ ║
║ 'Real ║ ║ ║
╠══════════╣ ╚═══════╗ ║
║ 'Complex ║ #f ║ ║
╚══════════╩══════════════════╩══════════╝)
https://docs.racket-lang.org/2d/index.html eq
mul pow
a a a 2
eq:
mul:
a
a
pow:
a
2
(eq (mul a
a)
(pow a
2))
or (eq
(mul
a
a
)
(pow
a
2
)
)
Actually, I'd suggest a slight improvement: x*x = x^2
The length people go to avoid Lisp, only to reinvent it, badly.
I’ve seen dozens of attempts to make S-Exp “better” even the original M-Exp. I also did some experiments myself. But at the end, I come back to goo’ol s-exp. Seems to be a maximum (or minimum) found just perchance.
(impl (impl p (impl q r)) (impl (impl p q) (impl p r)))
which, vertically indented in a transposed block, looks like this: * ( )
* i ( ) ( )
* m i p ( ) i ( ) ( )
p m i q r m i p q i p r
l p m p m m *
l p l p p *
l l l *
which, using transposed lines within the transposed block, finally looks like this: * ( )
* *impl* ( ) ( ) *
* *impl* *p* ( ) *impl* ( ) ( ) *
*impl* *q* *r* *impl* *p* *q* *impl* *p* *r* *
This time I won't make any judgements. Could be good, could be bad, you decide. (impl
(impl
p
(impl q r))
(impl
(impl p q)
(impl p r)))
It's clear when each section begins and ends and doesn't require complex parsing rules.It might even be easier to treat the input string as a 2D grid than as a sequence and have a parsing head that behaves like a 2x2 convolutional kernel...
This would make for either a great Advent of Code, or a nightmare interview question, I love it.
Blocks are parsed in the following way: when we get the beginning count of block opening characters, we move Y by one, loop right while whitespace, until we encounter ending count of block characters.
In transposed block, we just switch X and Y, it is easily done with pointers, and use the same code.
(fst-atom """ trd-atom frt-atom
""" 00001
asdf 00002 """ fth-atom)
qwer 00003 hahaha
zxcv """ hehehe
""" hohoho
"""
I'm not sure I'd like the above to be parseable.With a vertical script like japanese you could easily rotate the whole program 90 degrees to the right (as shown at the bottom of the landing page)
https://web.archive.org/web/20240904091932/https://lookalive...
{
"#!join": [
[
"A triangle with side of ",
"#& side",
" and base of ",
"#& base",
"has a hypotenuse of",
{
"#!sqrt": [
[
{
"#!sum": [
[
"#!multiply side side",
"#!multiply base base"
]
]
}
]
]
}
]
]
}
I kind of want something like, to borrow JSON-like syntax and gloss over namespacing issues:
(foo .
{type: listy-cons-cell
head: bar
tail: (baz quux)})
...which would be another way to say (foo bar baz quuz), but would make it possible to represent any data structure you like at the same level as atoms, strings, and lists.You can have vectors, hash maps, and sets in addition to lists, symbols, and keywords.
($define! foo
($bindings->environment
(bar "Hello World")
(baz 1234)
(qux #f)))
($remote-eval bar foo) ==> "Hello World"
foo ==> #[environment]
We could perhaps make something a bit more friendly. Lets create an encapsulated `struct` type which could give us the contents as a plain list, or let us look up each field: ($provide! ($struct struct? destruct $get)
($define! (struct-intro struct? struct-elim)
(make-encapsulation-type))
($define! destruct
($lambda (struct)
(cdr (struct-elim struct))))
($define! $get
($vau (struct member) e
($let ((record (car (struct-elim (eval struct e)))))
(eval member record))))
($define! zip
($lambda (keys values)
($if ($and? (null? keys) (null? values))
()
(cons (list (car keys) (car values)) (zip (cdr keys) (cdr values))))))
($define! $struct
($vau kvpairs env
($let* ((keys (map car kvpairs))
(values (map ($lambda (pair) (eval (cadr pair) env)) kvpairs))
(record (apply (wrap $bindings->environment) (zip keys values))))
(struct-intro (cons record values))))))
Example usage: ($define! foo
($struct
(bar "Hello World")
(baz (+ 12 43))
(qux #f))) ==> #inert
(struct? foo) ==> #t
(pair? foo) ==> #f
(environment? foo) ==> #f
(destruct foo) ==> ("Hello World" 55 #f)
($get foo bar) ==> "Hello World"
($get foo baz) ==> 55
($get foo qux) ==> #f
($get foo foo) ==> ERROR: Unbound symbol: foo
foo ==> #[encapsulation]
Kernel: https://web.cs.wpi.edu/~jshutt/kernel.htmlKlisp (essentially complete implementation of Kernel): https://github.com/dbohdan/klisp
(eq (mul (a a)) (pow (a 2)))
becomes eq
mul
a a
pow
a 2
Our visual system has the ability to detect implied straight lines (and other simple geometric outlines) from very small clues.
Therefore "seeing" the vertical lines implied by the indentation is effortless - so it's immediately obvious which elements belong to each other.
Indentation is an incredibly valuable "brain" hack that manages to instantly communicate hierarchy, not something to be sneered at.
We have no such innate ability to match parenthesis - determining hierarchy in a jumble of open and close parenthesis requires precise counting or, typically these days, tool/editor/IDE support.
Really? How do you see the difference between "TAB" and "SPACE SPACE TAB"?
eq (mul a a)
(pow a 2)
defun min (a b)
(if (a < b) a b)
IIRC the hack to support this at read time was minimal, and it made a big impact in terms of "mainstream appeal" eq :
mul a a
pow a 2
defun min (a b) :
if (< a b) a b
That means you can also have haskell-like continuations: seq :
eq (mul a a)
(pow a 2)
eq 4 3
> eq (* 3 3) (math:pow 3 2)
▶ $true
(function definitions on the other hand uses smalltalk/ruby style blocks)I should trademark this name.