Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Minor readability suggestions for the online MoonBit tour #360

Merged
merged 2 commits into from
Dec 17, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions moonbit-tour/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ const moonSvg = `<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0
`;

let theme: "light" | "dark" = "light";
// TODO: Preserve theme across multiple pages of the tour.

const themeButton = document.querySelector<HTMLDivElement>("#theme")!;

Expand Down
10 changes: 6 additions & 4 deletions moonbit-tour/tour/chapter1_basics/lesson10_test/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,16 @@ MoonBit has built-in testing support. There is no need to import or configure ex

**Note: this feature is not supported in this tour. You can try it in our [playground](try.moonbitlang.com) or in your terminal if the MoonBit toolchain is installed.**

In the first test block, we test some properties using the built-in functions assert_eq, assert_false, and assert_true. By running `moon test` in the terminal or clicking the test button, the tests will be executed.
In the first test block, we test some properties using the built-in functions `assert_eq`, `assert_false`, and `assert_true`.
By running `moon test` in the terminal or clicking the test button in your integrated development environment (IDE), the tests will be executed.

## Maintaining Tests

Sometimes it's tedious to maintain the expected value manually. MoonBit also supports built-in *snapshot tests*. Snapshot tests will run the tested code and store the expected result as a snapshot.
Sometimes it's tedious to maintain the expected value manually. MoonBit also supports built-in *snapshot tests*. Snapshot tests will run the tested code and store the expected result as a snapshot.

In the second test block, we use the `inspect` function to test the result of `fib` and the array's `map` method. By running `moon test --update` in the terminal or clicking the `Update test` button, the result will be automatically inserted as the second argument.
In the second test block, we use the `inspect` function to test the result of `fib` and the array's `map` method.
By running `moon test --update` in the terminal or clicking the `Update test` button in your IDE, the result will be automatically inserted as the second argument.

The next time you run the test, it will report any differences between the current result and the stored result. You can update the stored result to the new result by `--update` flag.
The next time you run the test, it will report any differences between the current result and the stored result. You can update the stored result to the new result by using the `--update` flag.


8 changes: 4 additions & 4 deletions moonbit-tour/tour/chapter1_basics/lesson1_variable/index.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
# Variables

The `let` keyword used to define a variable.
The `let` keyword is used to define a variable.

The type of the variable can be annotated by using a colon followed by the type.
It is optional, if not provided the type will be inferred from the value.
The type of the variable can be annotated by using a colon followed by the type.
It is optional; if not provided, the type will be inferred from the value.

Variables are immutable by default in MoonBit. You can add an extra `mut`
Variables are immutable by default in MoonBit. You can add an extra `mut`
keyword to make them mutable at the local level.

If you uncomment the `d = d + 1`, you will get an error.
6 changes: 4 additions & 2 deletions moonbit-tour/tour/chapter1_basics/lesson2_numbers/index.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
# Numbers

Integers and floats are the most common types in MoonBit, it can be represented in decimal, hexadecimal, octal, and binary, and you can use the underscore to separate digits for better readability.
Integers and floats are the most common types in MoonBit.
`Int`s can be represented in decimal, hexadecimal, octal, and binary,
and you can use the underscore to separate digits for better readability.
We call these *number literals*.

The `0xFFFF` is a hexadecimal number, `0o777` is an octal number, `0b1010` is a binary number,
The `0xFFFF` is a hexadecimal number, `0o777` is an octal number, `0b1010` is a binary number,
and `1_000_000` is a decimal number equivalent to `1000000`.


Expand Down
13 changes: 5 additions & 8 deletions moonbit-tour/tour/chapter1_basics/lesson4_array/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,23 @@

Array is a collection of elements that have the same type.

You can create an array by *array literal syntax*, which is a comma-separated list
You can create an array using *array literal syntax*, which is a comma-separated list
of elements enclosed in square brackets: `[1,2,3]`.

You can also create an array by using the `Array::make` function, which takes a size and an element value,
as shown in the example, `Array::make(4,1)` creates an array equal to `[1,1,1,1]`.

The `arr3` is an array consists of elements in `arr1`, elements in `arr2` and a few more numbers.
`..arr1` in square brackets is called *array spread*, which is used to expand an array into another array.
The `arr3` is an array consisting of elements in `arr1`, elements in `arr2` and a few more numbers.
`..arr1` in square brackets is called an *array spread*, which is used to expand an array into another array.

## Array view

You can use the `array[start:end]` syntax to get a view of the array from index `start` to `end` (inclusive). The `start` and `end` parts are optional. A view is a reference to the original array, it is used to avoid copying the array.
You can use the `array[start:end]` syntax to get a view of the array from index `start` to `end` (exclusive). The `start` and `end` parts are optional. A view is a reference to the original array and is used to avoid copying the array.

## Mutability of array

You may notice that we push an element to the array `arr1`, which changes the content of the array. How does that work if `arr1` is not marked with `mut`?

The answer is that the elements inside the array are mutable, which is **defined by the array type itself**. The `mut` keyword in the `let` statement is only used to determine whether the variable name you defined can be reassigned.

If you try to reassign `arr1` to another array like `arr1 = [1,2,3]`, you will get a compile error.



If you try to reassign `arr1` to another array like `arr1 = [1,2,3]`, you will get a compilation error.
8 changes: 5 additions & 3 deletions moonbit-tour/tour/chapter1_basics/lesson5_string/index.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
# String

A string is a sequence of characters encoded in UTF-16. In MoonBit, strings are immutable,
A string is a sequence of characters encoded in UTF-16. In MoonBit, strings are immutable,
which means you cannot change the elements inside a string.

MoonBit supports C-style escape characters in strings and chars, such as `\n`, `\t`, `\\`, `\"`, and `\'`.
MoonBit supports C-style escape characters in strings and chars, such as `\n` (newline),
`\t` (tab), `\\` (backslash), `\"` (double-quote), and `\'` (single-quote).

Unicode escape characters are also supported. You can use `\u{}` to represent a Unicode character by its code point.
Unicode escape characters are also supported. You can use `\u{...}` (where `...` represents
the Unicode character's hex code) to represent a Unicode character by its code point.

MoonBit also supports string interpolation written like `\{variable}`, which allows you to embed expressions into strings.

12 changes: 6 additions & 6 deletions moonbit-tour/tour/chapter1_basics/lesson6_tuple/index.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
# Tuple

Tuple is a collection of values that can have different types. It is immutable,
A tuple is a collection of values that can have different types. It is immutable,
which means that once it is created, it cannot be changed. It is created using
parentheses.

You can access the elements of tuple via the index: `tuple.0`, `tuple.1`, etc.

Tuple can be destructed via syntax like `let (a,b) = tuple`, the `tuple` in
right side is a tuple with two elements, and `a` and `b` are the variables to
store the elements. This is a special use case of *pattern matching*. We will
introduce *pattern matching* in the later chapter.
A tuple can be destructed via syntax like `let (a,b) = tuple`, where the `tuple` on
the right side is a tuple with two elements, and `a` and `b` are the variables to
store the elements. This is a special use case of *pattern matching* which we will
introduce in a later chapter.

It's common to use tuple to return multiple values from a function.
It's common to use a tuple to return multiple values from a function.

9 changes: 5 additions & 4 deletions moonbit-tour/tour/chapter1_basics/lesson7_map/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@

A map is a collection of key-value pairs. Each key is unique in the map, and all keys are associated with a value. It is a mutable collection.

Expression like `{"key1": value1, "key2": value2}` represents a map, called a *map literal*. If the key and value type of the map is basic type (`Int`, `String`,`Bool`, `Double`, etc.), it can be written as *map literal*.
An expression like `{"key1": value1, "key2": value2}` represents a map, called a *map literal*.
If the key and value types of the map are basic types (`Int`, `String`,`Bool`, `Double`, etc.),
then the map can be written as a *map literal*.

In other cases, you can create the map using the `Map::of` function. It takes an array of two-element tuples, where the first element is the key and the second element is the value.

Values in a map can be accessed by the key using the `map[key]` syntax.

The elements in a map can be updated by `map[key] = new_value`.
Values in a map can be accessed by the key using the `map[key]` syntax.

The elements in a map can be updated using the syntax: `map[key] = new_value`.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Control flow

In this example, we use for loops, while loops, and if-else expression to
In this example, we use for loops, while loops, and an if-else expression to
iterate over an array.

## For loop
Expand All @@ -25,5 +25,4 @@ The while loop is also similar to the C-style while loop.
It tests the condition before executing the loop body. If the condition is true,
it executes the loop body and repeats the process until the condition is false.

MoonBit also support `continue` and `break` in the loop.

MoonBit also supports both `continue` and `break` within the loop.
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,12 @@ In the first for-in loop, we iterate over an array. The loop will bind each
element to the variable `element` in each iteration.

We can also iterate over a map with key-value pairs. The second loop will bind
the key to the variable `k` and the value to the variable `v`.
the key to the first variable (`k`) and the value to the second variable (`v`).

Which collections can be iterated over with a for-in loop? And when does the for-in loop support two variables? The for-in loop functionality actually depends on the API of the collection:

- If the collection provides an `iter()` method to return a `Iter[V]` iterator, then the for-in loop can iterate over it.
- If the collection provides an `iter()` method to return an `Iter[V]` iterator, then the for-in loop can iterate over it with a single variable.

- If the collections provided `iter2()` methods to return a `Iter2[K,V]` iterator, you can use two variables to iterate over it.
- If the collection provides an `iter2()` method to return an `Iter2[K,V]` iterator, you can use two variables to iterate over it.

We will explain more details about the iterator in a later chapter.

10 changes: 5 additions & 5 deletions moonbit-tour/tour/chapter2_data_types/lesson1_struct/index.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
# Struct

Struct is a new type composed of other types.
Struct is a new type composed of other types.

In the example we define a struct `Point` with two fields, `x` and `y`, both of which are integers.
In the example we define a struct `Point` with two fields, `x` and `y`, both of which are integers.

We can create an instance of `Point` by using the `{ x: 3, y: 4 }`. The struct name can be omitted since the compiler can infer it from the labels `x` and `y`.
We can create an instance of `Point` by writing `{ x: 3, y: 4 }`. The struct name can be omitted since the compiler can infer it from the labels `x` and `y`.

We can also add a `Point::` prefix to create an instance explicitly to disambiguate.
We can also add a `Point::` prefix to create an instance explicitly to disambiguate its type.

Analogous to tuples, we can access the fields of a struct using the syntax `point.x`.

The `derive(Show)` after the struct definition means that we can print the struct using the `println` function.
The `derive(Show)` after the struct definition means that we can print the struct using the `println` function.

The fields of a struct are immutable by default; they can't be changed after they are created. There is a syntax called *functional update* that allows you to create a new struct with some fields updated.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,5 @@ Struct fields are immutable by default, but we can make them mutable by using th

In previous lessons, we have learned that collections in MoonBit can be either mutable or immutable. This is achieved by using the `mut` keyword in their type declaration.

The `MutPoint` struct in the example has two fields, mutable `mx` and immutable `y`. You can change the value of these fields via reassignment.



The `MutPoint` struct in the example has two fields, mutable `mx` and immutable `y`.
You can change the value of the `mx` field via reassignment but not the value of `y`.
9 changes: 6 additions & 3 deletions moonbit-tour/tour/chapter2_data_types/lesson3_enum/index.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
# Enum
# Enum

Enum used to define a type by enumerating its possible values. Unlike traditional enums, MoonBit enums can have data associated with each enumeration. We call each enumeration an *enum constructor*.
An enum is used to define a type by enumerating its possible values.
Unlike traditional enums, MoonBit enums can have data associated with each enumeration.
We call each enumeration an *enum constructor*.

In this example, we define an enum `Color`, which has five enum constructors: `Red`, `Green`, `Blue`, `RGB`, and `CMYK`. The `Red`, `Green`, and `Blue` directly represent a color it described, while `RGB` and `CMYK` have data associated with them.
In this example, we define an enum `Color`, which has five enum constructors: `Red`, `Green`, `Blue`, `RGB`, and `CMYK`.
The `Red`, `Green`, and `Blue` values directly represent the colors they describe, while `RGB` and `CMYK` have data associated with them.

Values like `Red` and `RGB(255,255,255)` are both instances of the `Color` type. To create an instance more explicitly, you can use `Color::Red`, similar to creating an instance of a struct.

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Option

`Option[Char]` is an enum represents a `Char` value that may or may not be present. It is a common way to handle exceptional case.
`Option[Char]` is an enum that represents a `Char` value that may or may not be present. It is a common way to handle exceptional cases.

- `None` means the value is missing.
- `Some(e)` is a wrapper that contains the value `e`.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Result

Similar to `Option[Char]`, the enum `Result[Char, String]` represents a `Char` value that may or may not be present. Otherwise, it can contain an error message of type `String`.
Similar to `Option[Char]`, the enum `Result[Char, String]` represents a `Char` value that may or may not be present. If not present, it can contain an error message of type `String`.

- `Err("error message")` means the value is missing, and the error message is provided.
- `Ok('h')` is a wrapper that contains the value `'h'`.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
# Pattern Matching

We have seen pattern matching in the previous example.
It's a powerful feature in MoonBit that can be used in many places. It can help you test conditions conveniently and effectively, making your program more precise and robust.
It's a powerful feature in MoonBit that can be used in many places. It can help you test conditions conveniently and effectively, making your programs more precise and robust.

In this example, we give some basic use cases of pattern matching. Some other languages call it "destructuring" or "structured bindings", a way to extract values from a complex data structure.
In this example, we give some basic use cases of pattern matching. Some other languages call it "destructuring" or "structured bindings", a way to extract values from a complex data structure.

"Destructuring" is just a subset of this feature.
In MoonBit, almost every type you can construct can have a form to "destruct", which we call a *pattern*.
In MoonBit, almost every type you can construct can have a form to "destruct", which we call a *pattern*.
Original file line number Diff line number Diff line change
@@ -1,22 +1,26 @@
# Pattern in let and match

There are two common place to use pattern: let and match.
There are two common places to use a pattern: `let` and `match`.

We defined a `Resource` type, it describes a file system. The `Resource` can be a text file, an image, or a folder associated with more files.
In this example, we define a `Resource` type that describes a file system.
The `Resource` can be a text file, an image, or a folder associated with more files.

## Pattern in let statement

In a let statement, the left side of `=` can be a pattern, we known that assets is a folder so just use `let Folder(top_level) = assets` to match it and extract the inside map.
In a `let` statement, the left side of `=` can be a pattern.
We know that `assets` is a folder so we just use `let Folder(top_level) = assets` to match it and extract the value into the immutable variable `top_level`.

You may notice that there is a partial match warning because the resource can also be `Image` or `TextFile`. **Partial match make the program more fragile: the pattern matching will fail in other cases and lead to the program aborting.** Practically, the match expression is used more frequently.
You may notice that there is a partial match warning because the resource can also be `Image` or `TextFile`.
**Partial matches make the program more fragile: the pattern matching may fail in other cases and lead to the program aborting.**
Practically, the `match` expression is used more frequently than the `let` statement.

## Pattern in match expression

The `count` function traverse the input `res` recursively and return the count of `Image` and `TextFile`, using match expression.
The `count` function traverses the input `res` recursively and returns the count of `Image` and `TextFile`, using a `match` expression.

Match expressions have *first match semantics*. They will try to find the first matching pattern from the first case to the last case and execute the corresponding expression. If no pattern matches, the program will abort.
Match expressions have *first match semantics*. They will try to find the first matching pattern sequentially from the first case to the last case and execute the corresponding matched expression. If no pattern matches, the program will abort.

The match expression has a `Int` return value because all the case result in same value type `Int`.

Patterns can be nested. If you don't care about the data associated with the enum constructor, you can use the *any pattern*, written as `_`, instead of introducing a new variable. It means discarding that value.
The match expression has an `Int` return value because all the cases result in the same value type `Int`.

Patterns can be nested. If you don't care about the data associated with the enum constructor, you can use the *any pattern*, written as `_`, instead of introducing a new variable.
The underscore means that the value is discarded.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Constant pattern

Almost all constant in MoonBit can be represented as a constant pattern.

Almost all constants in MoonBit can be represented as a constant match pattern
on the left side of the `=>`.
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Tuple pattern

Use tuple pattern to match multiple conditions at once.
Use a tuple pattern to match multiple conditions at once.

This example simulates *logical and* and *logical or* operation via pattern matching.
This example simulates *logical and* and *logical or* operations via pattern matching.

In this scenario, the overhead of creating the tuple in the condition will be optimized out by the compiler.

Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
# Array Pattern
# Array Pattern

Array pattern is a sequence of patterns enclosed in `[]` that matches an array.
An array pattern is a sequence of patterns enclosed in `[]` that matches an array.

You can use `..` to match the rest of the array at the start or end, or the middle elements of the array.
You can use `..` to match the rest of the array at the start, end, or middle elements of the array.

In an array pattern, the `..` part can be bound to a new variable via an *alias pattern*. The type of that variable is `ArrayView`. The `sum` function uses this feature to calculate the sum of the array recursively.




Loading
Loading