Skip to content

Commit

Permalink
doc: Update 'quick-guide.md'
Browse files Browse the repository at this point in the history
  • Loading branch information
lhmouse committed Nov 30, 2023
1 parent a218af3 commit 8576953
Showing 1 changed file with 101 additions and 11 deletions.
112 changes: 101 additions & 11 deletions doc/quick-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ as other scripting languages. However there are some fundamental differences:
attempting to modify temporary values will effect runtime errors. This
applies similarly to function results.

## 101
## Course 101

In the first class of every programming language, we are taught to output the
magic string `"hello world!"`. This can be done by calling the `putln()`
Expand All @@ -47,12 +47,11 @@ placeholder `$1` is to be replaced with the 1st argument that follows it, and

As our program no longer first into one line, we need to enable the _heredoc_
mode. The `:heredoc` command takes an arbitrary string that will mark the end
of a single snippet. In this example we use `end_of_my_code`, so our program
looks like:
of a single snippet. In this example we use `@@`, so our program looks like:

```
#2:1> :heredoc end_of_my_code
* the next snippet will be terminated by `end_of_my_code`
#2:1> :heredoc @@
* the next snippet will be terminated by `@@`
#3:1> var sum = 0;
2>
Expand All @@ -61,7 +60,7 @@ looks like:
5>
6> std.io.putfln("sum = $1", sum);
7>
8> end_of_my_code
8> @@
* running 'snippet #3'...
sum = 5050
* result #3: void
Expand All @@ -73,8 +72,8 @@ Our program uses `getln()` to read our input, then converts it to an integer,
and checks whether it is correct:

```
#4:1> :heredoc end_of_my_code
* the next snippet will be terminated by `end_of_my_code`
#4:1> :heredoc @@
* the next snippet will be terminated by `@@`
#5:1> var num = 1 + __ifloor std.numeric.random(100); // 1 - 100
2> std.io.putln("number generated; guess now!");
Expand All @@ -99,8 +98,8 @@ and checks whether it is correct:
21>
22> std.io.putfln("my number was $1. have a nice day.", num);
23>
24> end_of_my_code
* running 'snippet #2'...
24> @@
* running 'snippet #5'...
number generated; guess now!
50
your answer was greater; try again.
Expand All @@ -115,5 +114,96 @@ your answer was greater; try again.
30
you got it!
my number was 30. have a nice day.
* result #2: void
* result #5: void
```

## Lambdas

The most common scenario where lambdas are useful is probably sorting. For
example, this sorts an array of integers in ascending order:

```
#1:1> std.array.sort([8,4,6,9,2,5,3,0,1,7])
* running 'expression #1'...
* result #1: array(10) [
0 = integer 0;
1 = integer 1;
2 = integer 2;
3 = integer 3;
4 = integer 4;
5 = integer 5;
6 = integer 6;
7 = integer 7;
8 = integer 8;
9 = integer 9;
];
```

But what if we want to sort it in descending order instead? First, let's take
a look at the prototype of `std.array.sort`:

```
#2:1> std.array.sort
* running 'expression #2'...
* result #2: function [[`std.array.sort(data, [comparator])` at 'asteria/library/array.cpp:1058']];
```

So it can take an optional `comparator` function. Every standard function
which takes a `comparator` function has the same requirement on it, which is

1. It takes two arguments, namely `x` and `y`.
2. If `x` is less than `y`, `comparator(x, y)` returns a negative number.
3. If `x` is greater than `y`, `comparator(x, y)` returns a positive number.
4. If `x` is equivalent to `y`, `comparator(x, y)` returns zero.

Other results usually indicate that `x` and `y` are unordered, and are likely
to cause exceptions to be thrown. This specification matches the built-in
'spaceship' operator `<=>`. Therefore, in order to sort an array in reverse
order, we need to define a lambda, i.e. an anonymous function, that returns
the opposite of the default comparison result. There are actually two ways to
do this, either `func(x, y) { return -(x <=> y); }` or `func(x, y) { return y
<=> x; }`. We use the second form, and it looks like

```
#3:1> std.array.sort([8,4,6,9,2,5,3,0,1,7], \
2> func(x, y) { return y <=> x; })
* running 'expression #3'...
* result #3: array(10) [
0 = integer 9;
1 = integer 8;
2 = integer 7;
3 = integer 6;
4 = integer 5;
5 = integer 4;
6 = integer 3;
7 = integer 2;
8 = integer 1;
9 = integer 0;
];
```

Another example is about how to sort an array of integers by their final
digits, as in

```
#4:1> std.array.sort([58,34,16,89,62,95,73,41,27], \
2> func(x, y) { return x % 10 <=> y % 10; })
* running 'expression #4'...
* result #4: array(9) [
0 = integer 41;
1 = integer 62;
2 = integer 73;
3 = integer 34;
4 = integer 95;
5 = integer 16;
6 = integer 27;
7 = integer 58;
8 = integer 89;
];
```

Lambdas are (sub-)expressions. A lambda that returns something has a short
form. For example, `func(x, y) { return x + y; }` can be abbreviated as just
`func(x, y) = x + y`, without `{ return` or `; }`. Likewise, `func(x, y) {
return ref x.foo(y); }` can be abbreviated as `func(x, y) -> x.foo(y)`, also
without `{ return ref` or `; }`.

0 comments on commit 8576953

Please sign in to comment.