aboutsummaryrefslogtreecommitdiff
path: root/README.md
blob: 0eb2f84f2336aadaea3d4312ed8796ee62230775 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
# 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.