Skip to content

Commit

Permalink
fix: update code to match latest moonbit
Browse files Browse the repository at this point in the history
  • Loading branch information
skylee03 committed Jul 2, 2024
1 parent 9ef9952 commit 22d0576
Show file tree
Hide file tree
Showing 7 changed files with 39 additions and 39 deletions.
8 changes: 4 additions & 4 deletions docs/01-program-design.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,8 @@ The process of writing test cases not only helps in validating the solution but

```moonbit
test {
@assertion.assert_eq(num_water_bottles(9, 3), 13)? // 9 + 3 + 1 = 13
@assertion.assert_eq(num_water_bottles(15, 4), 19)?
@test.eq(num_water_bottles(9, 3), 13)! // 9 + 3 + 1 = 13
@test.eq(num_water_bottles(15, 4), 19)!
}
```

Expand All @@ -91,8 +91,8 @@ fn num_water_bottles(num_bottles: Int, num_exchange: Int) -> Int {
}
test {
@assertion.assert_eq(num_water_bottles(9, 3), 13)? // 9 + 3 + 1 = 13
@assertion.assert_eq(num_water_bottles(15, 4), 19)?
@test.eq(num_water_bottles(9, 3), 13)! // 9 + 3 + 1 = 13
@test.eq(num_water_bottles(15, 4), 19)!
}
```

Expand Down
6 changes: 3 additions & 3 deletions docs/02-development-environments-expressions.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,12 @@ fn num_water_bottles(num_bottles: Int, num_exchange: Int) -> Int {
// test block
test {
// statements
@assertion.assert_eq(num_water_bottles(9, 3), 13)?
@assertion.assert_eq(num_water_bottles(15, 4), 19)?
@test.eq(num_water_bottles(9, 3), 13)!
@test.eq(num_water_bottles(15, 4), 19)!
}
```

In the above program, a top-level function and a test block are defined. In the top-level function, a local function is defined and invoked. The value of the local function is a conditional expression. In the true branch, two variable bindings are defined, and the local function is called; whereas in the false branch, a simple addition operation is executed. In the test block, two assertion commands are used to judge the correctness of our program.
In the above program, a top-level function and a test block are defined. In the top-level function, a local function is defined and invoked. The value of the local function is a conditional expression. In the true branch, two variable bindings are defined, and the local function is called; whereas in the false branch, a simple addition operation is executed. In the test block, two test commands are used to judge the correctness of our program.

Since this program does not generate any output, how exactly is it executed?

Expand Down
6 changes: 3 additions & 3 deletions docs/04-tuples-structs-enums.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ let accepted: Bool = accept(({other: 2, val: 1}: A))
Pattern matching is another way to access tuples and structures.

```moonbit
fn head_opt(list: List[Int]) -> Option[Int] {
fn head_opt(list: @immut/list.List[Int]) -> Option[Int] {
match list {
Nil => None
Cons(head, tail) => Some(head)
Expand Down Expand Up @@ -140,7 +140,7 @@ fn is_zero(i: Int) -> Bool {
In the examples above, we matched numbers. Here we use the pipe symbol (the `or` pattern) to simultaneously match multiple possible values. The underscore (`_`) is the wildcard to match all remaining cases. We can nest patterns in constructors, or bind corresponding structures with identifiers.

```moonbit
fn contains_zero(l: List[Int]) -> Bool {
fn contains_zero(l: @immut/list.List[Int]) -> Bool {
match l {
Nil => false
Cons(0, _) => true
Expand Down Expand Up @@ -177,7 +177,7 @@ Tuples' patterns are just like their definitions, enclosed in parentheses and se
Here is another example for better understanding how to use nested patterns. The `zip` function combines two lists into a new list of pairs like a zipper. The length of the resulting list is the minimum of the lengths of the input lists. Given the lists `[1, 2, 3]` and `['a', 'b', 'c', 'd']`, the zipped list would be `[(1, 'a'), (2, 'b'), (3, 'c')]`.

```moonbit
fn zip(l1: List[Int], l2: List[Char]) -> List[(Int, Char)] {
fn zip(l1: @immut/list.List[Int], l2: @immut/list.List[Char]) -> @immut/list.List[(Int, Char)] {
match (l1, l2) {
(Cons(hd, tl), Cons(hd2, tl2)) => Cons((hd, hd2), zip(tl, tl2))
_ => Nil
Expand Down
16 changes: 8 additions & 8 deletions docs/05-trees.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,8 @@ fn pop[T](q: Queue[T]) -> (Option[T], Queue[T])
```moonbit
struct Queue[T] {
front:List[T]
back:List[T]
front:@immut/list.List[T]
back:@immut/list.List[T]
}
/// `Queue::default[T]()`
Expand All @@ -125,10 +125,10 @@ fn empty[T]() -> Queue[T] {
Queue::default()
}
/// `from_list[T](front: List[T])`
/// `from_list[T](front: @immut/list.List[T])`
///
/// Create queue from a list 从列表创建队列
fn Queue::from_list[T](front: List[T]) -> Queue[T] {
fn Queue::from_list[T](front: @immut/list.List[T]) -> Queue[T] {
{ front:front, back:Nil }
}
Expand All @@ -142,14 +142,14 @@ fn Queue::is_empty[T](q: Queue[T]) -> Bool {
}
}
/// `list_rev[T](xs: List[T])`
/// `list_rev[T](xs: @immut/list.List[T])`
///
/// Reverse a list with tail recursion 基于尾递归的列表反转
fn list_rev[T](xs: List[T]) -> List[T] {
fn go(acc, xs: List[T]) {
fn list_rev[T](xs: @immut/list.List[T]) -> @immut/list.List[T] {
fn go(acc, xs: @immut/list.List[T]) {
match xs {
Nil => acc
Cons(x, rest) => go((Cons(x, acc) : List[T]), rest)
Cons(x, rest) => go((Cons(x, acc) : @immut/list.List[T]), rest)
}
}
Expand Down
18 changes: 9 additions & 9 deletions docs/06-generics-higher-order-functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ Here is the code for the queue. You can see that we extensively apply generics,
This section continues to focus on how to use the features provided by MoonBit to reduce repetitive code and enhance code reusability. So, let’s start with an example.

```moonbit
fn sum(list: List[Int]) -> Int {
fn sum(list: @immut/list.List[Int]) -> Int {
match list {
Nil => 0
Cons(hd, tl) => hd + sum(tl)
Expand All @@ -206,7 +206,7 @@ fn sum(list: List[Int]) -> Int {
Consider some operations on lists. For instance, to sum an integer list, we use structural recursion with the following code: if empty, the sum is 0; otherwise, the sum is the current value plus the sum of the remaining list elements.

```moonbit
fn length[T](list: List[T]) -> Int {
fn length[T](list: @immut/list.List[T]) -> Int {
match list {
Nil => 0
Cons(hd, tl) => 1 + length(tl)
Expand All @@ -223,7 +223,7 @@ Notice that these two structures have considerable similarities: both are struct
This brings us to the point that in MoonBit, functions are first-class citizens. This means that functions can be passed as parameters and can also be stored as results. For instance, the structure we just described can be defined as the function shown below, where `f` is passed as a parameter and used in line four for calculation.

```moonbit
fn fold_right[A, B](list: List[A], f: (A, B) -> B, b: B) -> B {
fn fold_right[A, B](list: @immut/list.List[A], f: (A, B) -> B, b: B) -> B {
match list {
Nil => b
Cons(hd, tl) => f(hd, fold_right(tl, f, b))
Expand Down Expand Up @@ -284,7 +284,7 @@ For example, the function type from integer to integer, would be `(Int) -> Int`.
Here are a few more common applications of higher-order functions. Higher-order functions are functions that accept functions. `fold_right`, which we just saw, is a common example. Below, we draw its expression tree.

```moonbit no-check
fn fold_right[A, B](list: List[A], f: (A, B) -> B, b: B) -> B {
fn fold_right[A, B](list: @immut/list.List[A], f: (A, B) -> B, b: B) -> B {
match list {
Nil => b
Cons(hd, tl) => f(hd, fold_right(tl, f, b))
Expand All @@ -297,7 +297,7 @@ fn fold_right[A, B](list: List[A], f: (A, B) -> B, b: B) -> B {
You can see that for a list from 1 to 3, `f` is applied to the current element and the result of the remaining elements each time, thus it looks like we're building a fold from right to left, one by one, to finally get a result. Therefore, this function is called `fold_right`. If we change the direction, folding the list from left to right, then we get `fold_left`.

```moonbit
fn fold_left[A, B](list: List[A], f: (B, A) -> B, b: B) -> B {
fn fold_left[A, B](list: @immut/list.List[A], f: (B, A) -> B, b: B) -> B {
match list {
Nil => b
Cons(hd, tl) => fold_left(tl, f, f(b, hd))
Expand All @@ -315,20 +315,20 @@ Another common application of higher-order functions is to map each element of a

```moonbit no-check
struct PersonalInfo { name: String; age: Int }
fn map[A, B](self: List[A], f: (A) -> B) -> List[B] {
fn map[A, B](self: @immut/list.List[A], f: (A) -> B) -> @immut/list.List[B] {
match list {
Nil => Nil
Cons(hd, tl) => Cons(f(hd), map(tl, f))
}
}
let infos: List[PersonalInfo] = ???
let names: List[String] = infos.map(fn (info) { info.name })
let infos: @immut/list.List[PersonalInfo] = ???
let names: @immut/list.List[String] = infos.map(fn (info) { info.name })
```

For example, if we have some people's information and we only need their names, then we can use the mapping function `map`, which accepts `f` as a parameter, to map each element in the list one by one, finally obtaining a new list where the type of elements has become `B`. This function's implementation is very simple. What we need is also structural recursion. The last application is as shown in line 8. Maybe you feel like you've seen this `map` structure before: structural recursion, a default value for the empty case, and a binary operation processing the current value combined with the recursive result when not empty. Indeed, `map` can be entirely implemented using `fold_right`, where the default value is an empty list, and the binary operation is the `Cons` constructor.

```moonbit
fn map[A, B](list: List[A], f: (A) -> B) -> List[B] {
fn map[A, B](list: @immut/list.List[A], f: (A) -> B) -> @immut/list.List[B] {
fold_right(list, fn (value, cumulator) { Cons(f(value), cumulator) }, Nil)
}
```
Expand Down
6 changes: 3 additions & 3 deletions docs/11-parser.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,11 @@ fn pchar(predicate : (Char) -> Bool) -> Lexer[Char] {
} },) }
test {
inspect(pchar(fn { ch => ch == 'a' }).parse("asdf"), content="Some((a, sdf))")?
inspect(pchar(fn { ch => ch == 'a' }).parse("asdf"), content="Some((a, sdf))")!
inspect(pchar(fn {
'a' => true
_ => false
},).parse("sdf"),content="None",)?
},).parse("sdf"),content="None",)!
}
```

Expand Down Expand Up @@ -169,7 +169,7 @@ let tokens : Lexer[@immut/list.List[Token]] =
.many()
test{
inspect(tokens.parse("-10123+-+523 103 ( 5) ) "), content="Some((List::[Minus, Value(10123), Plus, Minus, Plus, Value(523), Value(103), LParen, Value(5), RParen, RParen], ))")?
inspect(tokens.parse("-10123+-+523 103 ( 5) ) "), content="Some((List::[Minus, Value(10123), Plus, Minus, Plus, Value(523), Value(103), LParen, Value(5), RParen, RParen], ))")!
}
```

Expand Down
18 changes: 9 additions & 9 deletions docs/12-autodiff.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,11 +108,11 @@ fn example() -> Symbol {
test "Symbolic differentiation" {
let input : Array[Double] = [10.0, 100.0]
let symbol : Symbol = example() // Abstract syntax tree of the function
@assertion.assert_eq(symbol.compute(input), 600.0)?
@test.eq(symbol.compute(input), 600.0)!
// Expression of df/dx
inspect(symbol.differentiate(0),
content="Add(Add(Mul(Mul(Constant(5.0), Var(0)), Constant(1.0)), Mul(Add(Mul(Constant(5.0), Constant(1.0)), Mul(Constant(0.0), Var(0))), Var(0))), Constant(0.0))")?
@assertion.assert_eq(symbol.differentiate(0).compute(input), 100.0)?
content="Add(Add(Mul(Mul(Constant(5.0), Var(0)), Constant(1.0)), Mul(Add(Mul(Constant(5.0), Constant(1.0)), Mul(Constant(0.0), Var(0))), Var(0))), Constant(0.0))")!
@test.eq(symbol.differentiate(0).compute(input), 100.0)!
}
```

Expand Down Expand Up @@ -216,10 +216,10 @@ Finally, we use the previously defined example with conditionals to calculate de
```moonbit
test "Forward differentiation" {
// Forward differentiation with abstraction
inspect(relu(Forward::var(10.0, true)), content="{value: 10.0, derivative: 1.0}")?
inspect(relu(Forward::var(-10.0, true)), content="{value: 0.0, derivative: 0.0}")?
inspect(relu(Forward::var(10.0, true)), content="{value: 10.0, derivative: 1.0}")!
inspect(relu(Forward::var(-10.0, true)), content="{value: 0.0, derivative: 0.0}")!
// f(x, y) = x * y => df/dy(10, 100)
inspect(Forward::var(10.0, false) * Forward::var(100.0, true), ~content="{value: 1000.0, derivative: 10.0}")?
inspect(Forward::var(10.0, false) * Forward::var(100.0, true), ~content="{value: 1000.0, derivative: 10.0}")!
}
```

Expand Down Expand Up @@ -286,8 +286,8 @@ test "Backward differentiation" {
let x = Backward::var(10.0, diff_x)
let y = Backward::var(100.0, diff_y)
(x * y).backward(1.0) // df / df = 1
inspect(diff_x, content="{val: 100.0}")?
inspect(diff_y, content="{val: 10.0}")?
inspect(diff_x, content="{val: 100.0}")!
inspect(diff_y, content="{val: 10.0}")!
}
```

Expand Down Expand Up @@ -325,7 +325,7 @@ test "Newton's method" {
}
continue Forward::var(x.value - value / derivative, true)
}
} |> @assertion.assert_eq(0.37851665401644224))?
} |> @test.eq(0.37851665401644224))!
}
```

Expand Down

0 comments on commit 22d0576

Please sign in to comment.