Lyn
Old swedish for maple.
Scheme is cool
...but has too many parentheses.
TCL is cool (yes, it really is)
...but littering $ all over the place is annoying.
Can we build something in-between?
Maybe. lyn is effectively a pre-processor for GNU Guile, adopting TCL's
'everything is a command' attitude while keeping Scheme semantics.
Let's start with an example, examples/guile.lyn:
define-syntax-rule (for init condition post body) {
expand init
do () ((not (expand condition))) {
expand body
expand post
}
}
define (sum n) {
define s 0
for (define i 0) (< i n) (set! i (1+ i)) {
set! s (+ s i)
}
get s
}
display (sum 1000000)
newline
If you're familiar with Scheme, this should look eerily familiar.
Effectively, a command starts with a thing to apply, follows with some arguments
and ends with a newline or ;. () applies a command to be used as an
argument, and {} specifies a list of commands. The top-level can also be
thought of as a block of commands.
When encountering a {, a matching } must be found before the command can be
finished. {} can itself contain newlines just fine.
A command can also be continued over multiple lines by using \, as in
examples/multiline.lyn:
if (< 10 20) \
{display "math works"; newline} \
{display "what"; newline}
There are two 'builtins' beyond what GNU Guile provides (all GNU Guile functions
can be called as commands), namely get and expand. They're effectively the
identity commands, i.e. get returns the value that was passed into it, and
expand expands a macro as if expand weren't there. These are useful because,
again, literally everythin is a command, so if you want to return a value you
can't just write arg as the last element of a (begin ...) or whatever,
because that value will be interpreted as a command. Same thing with macros.
Note that values is effectively the same thing as get, but I think get has
a nicer symmetry with let/set. macroexpand is (maybe somewhat
surprisingly) not equivalent to expand, as macroexpand can't handle
(define ...).
Since ; ends commands, # is used for comments instead.
The current implementation just outputs all code into /tmp/output.scm.
Terrible, I know, but good enough to start playing around with it.
Have a look at that file to see just how closely this syntax matches Scheme,
while (IMO) being easier to read. In particular I find this style to be easier
to write, as I sometimes find that I have to count how many parentheses deep
some expression is. I'm aware that there are tools that help with this, but I
tend to want to have as little between me and my code.
Drawbacks
-
Code generation is arguably not as trivial as with S-expressions. Ideally traditional Scheme functions could be interleaved with this syntax, though I haven't really looked into this option.
-
Certain coding styles (like placing
{on a new line) are more clumsy to use -
The current implementation parses
()with multiple commands but produces incorrect Scheme. I'm not sure whether to fix the outputting or disallow multiple commands within()(that's what{}is for)
Isn't this all a bit silly?
Yes.
Schemers are presumably used to the parentheses and would prefer them over this, while the TCL crowd likely don't like the shift away from user interfaces. I don't expect anyone to really have any interest in this thing, but if I'd get to choose I would probably want to use a scripting language like this over any other current alternatives, of which there are many excellent ones.
Building and running
make, after which ./lyn examples/guile.scm for example. REPL not supported
at the moment, though it probably could be added.
