Skip to content

Commit

Permalink
Use plain functions for IntMap
Browse files Browse the repository at this point in the history
  • Loading branch information
skylee03 authored and peter-jerry-ye committed Apr 15, 2024
1 parent 2d1108d commit ca2c495
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 28 deletions.
41 changes: 27 additions & 14 deletions course3/course_en.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,19 @@ style: |
<!--
```moonbit
let pi = 3.1415
fn put(map: @map.Map[Int, Int64], num: Int, result: Int64) -> @map.Map[Int, Int64] {
map.insert(num, result)
}
fn get(map: @map.Map[Int, Int64], num: Int) -> Option[Int64] {
map.lookup(num)
}
fn make() -> @map.Map[Int, Int64] {
@map.empty()
}
```
-->

Expand Down Expand Up @@ -594,9 +607,9 @@ A large number of duplicated subproblems was observed.
- We need a data structure whose average access efficiency is independent of the data size, and it should have the following interfaces:

```moonbit no-check
fn empty() -> IntMap // Create
fn insert(self: IntMap, key: Int, value: Int64) -> IntMap // Store
fn lookup(self: IntMap, key: Int) -> Option[Int64] // Retrieve
fn make() -> IntMap // Create
fn put(map: IntMap, num: Int, value: Int64) -> IntMap // Store
fn get(map: IntMap, num: Int) -> Option[Int64] // Retrieve
```

- There are many siutable data structures, e.g., `@map.Map[Int, Int64]`.
Expand All @@ -614,16 +627,16 @@ fn lookup(self: IntMap, key: Int) -> Option[Int64] // Retrieve
```moonbit expr
fn fib1(num: Int) -> Int64 {
fn aux(num: Int, map: @map.Map[Int, Int64]) -> (Int64, @map.Map[Int, Int64]) {
match map.lookup(num) {
match get(map, num) {
Some(result) => (result, map)
None => {
let (result_1, map_1) = aux(num - 1, map)
let (result_2, map_2) = aux(num - 2, map_1)
(result_1 + result_2, map_2.insert(num, result_1 + result_2))
(result_1 + result_2, put(map_2, num, result_1 + result_2))
}
}
}
let map = @map.empty().insert(1, 1L).insert(2, 1L)
let map = put(put(make(), 1, 1L), 2, 1L)
aux(num, map).0
}
```
Expand All @@ -638,15 +651,15 @@ To simplify the code, MoonBit supports mutable variables.
```moonbit expr
fn fib1_mut(num: Int) -> Int64 {
// Declare a mutable variable with let mut
let mut map = @map.empty().insert(1, 1L).insert(2, 1L)
let mut map = put(put(make(), 1, 1L), 2, 1L)
fn aux(num: Int) -> Int64 {
match map.lookup(num) {
match get(map, num) {
Some(result) => result
None => {
let result_1 = aux(num - 1)
let result_2 = aux(num - 2)
// Update the binding with <variable> = <expression>
map = map.insert(num, result_1 + result_2)
map = put(map, num, result_1 + result_2)
result_1 + result_2
}
}
Expand All @@ -664,12 +677,12 @@ Starting from the first one, calculate and store the subsequent items sequential
```moonbit expr
fn fib2(num: Int) -> Int64 {
fn aux(n: Int, map: @map.Map[Int, Int64]) -> Int64 {
let result = get_or_else(map.lookup(n - 1), 1L) +
get_or_else(map.lookup(n - 2), 1L)
if n == num { result }
else { aux(n + 1, map.insert(n, result)) }
let result = get_or_else(get(map, n - 1), 1L) +
get_or_else(get(map, n - 2), 1L)
if n == num { result }
else { aux(n + 1, put(map, n, result)) }
}
let map = @map.empty().insert(0, 0L).insert(1, 1L)
let map = put(put(make(), 0, 0L), 1, 1L)
aux(1, map)
}
```
Expand Down
41 changes: 27 additions & 14 deletions course3/lecture_en.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,19 @@
<!--
```moonbit
let pi = 3.1415
fn put(map: @map.Map[Int, Int64], num: Int, result: Int64) -> @map.Map[Int, Int64] {
map.insert(num, result)
}
fn get(map: @map.Map[Int, Int64], num: Int) -> Option[Int64] {
map.lookup(num)
}
fn make() -> @map.Map[Int, Int64] {
@map.empty()
}
```
-->

Expand Down Expand Up @@ -473,9 +486,9 @@ First, let's try a top-down implementation.
To cache the previous calculation results, we need a suitable data structure. Since the number of results we cache will grow with the size of the problem, the average access efficiency of the data structure should be independent of the data size. Let's call it `IntMap`, then following our standard workflow, we should now define the interfaces:

```moonbit no-check
fn empty() -> IntMap // Create
fn insert(self: IntMap, key: Int, value: Int64) -> IntMap // Store
fn lookup(self: IntMap, key: Int) -> Option[Int64] // Retrieve
fn make() -> IntMap // Create
fn put(map: IntMap, num: Int, value: Int64) -> IntMap // Store
fn get(map: IntMap, num: Int) -> Option[Int64] // Retrieve
```

In other words, we should be able to perform the following operations using an `IntMap`: create an empty map, insert a key-value pair into it, and look up the value corresponding to a given key.
Expand All @@ -487,16 +500,16 @@ In the top-down implementation, before each computation, we first check if our d
```moonbit expr
fn fib1(num: Int) -> Int64 {
fn aux(num: Int, map: @map.Map[Int, Int64]) -> (Int64, @map.Map[Int, Int64]) {
match map.lookup(num) {
match get(map, num) {
Some(result) => (result, map)
None => {
let (result_1, map_1) = aux(num - 1, map)
let (result_2, map_2) = aux(num - 2, map_1)
(result_1 + result_2, map_2.insert(num, result_1 + result_2))
(result_1 + result_2, put(map_2, num, result_1 + result_2))
}
}
}
let map = @map.empty().insert(1, 1L).insert(2, 1L)
let map = put(put(make(), 1, 1L), 2, 1L)
aux(num, map).0
}
```
Expand All @@ -510,15 +523,15 @@ In MoonBit, all variables are immutable by default. In order to declare a mutabl
```moonbit expr
fn fib1_mut(num: Int) -> Int64 {
// Declare a mutable variable with let mut
let mut map = @map.empty().insert(1, 1L).insert(2, 1L)
let mut map = put(put(make(), 1, 1L), 2, 1L)
fn aux(num: Int) -> Int64 {
match map.lookup(num) {
match get(map, num) {
Some(result) => result
None => {
let result_1 = aux(num - 1)
let result_2 = aux(num - 2)
// Update the binding with <variable> = <expression>
map = map.insert(num, result_1 + result_2)
map = put(map, num, result_1 + result_2)
result_1 + result_2
}
}
Expand All @@ -534,12 +547,12 @@ In the bottom-up implementation, we typically start from the smallest subproblem
```moonbit expr
fn fib2(num: Int) -> Int64 {
fn aux(n: Int, map: @map.Map[Int, Int64]) -> Int64 {
let result = get_or_else(map.lookup(n - 1), 1L) +
get_or_else(map.lookup(n - 2), 1L)
if n == num { result }
else { aux(n + 1, map.insert(n, result)) }
let result = get_or_else(get(map, n - 1), 1L) +
get_or_else(get(map, n - 2), 1L)
if n == num { result }
else { aux(n + 1, put(map, n, result)) }
}
let map = @map.empty().insert(0, 0L).insert(1, 1L)
let map = put(put(make(), 0, 0L), 1, 1L)
aux(1, map)
}
```
Expand Down

0 comments on commit ca2c495

Please sign in to comment.