diff --git a/docs/builtins.md b/docs/builtins.md index 122d9873..ee6f4c17 100644 --- a/docs/builtins.md +++ b/docs/builtins.md @@ -190,15 +190,15 @@ def Maybe/unwrap(m: Maybe(T)) -> T: ## Map ```python -type Map: - Node { value ~left ~right } - Leaf +type Map(T): + Node { value: Maybe(T), ~left: Map(T), ~right: Map(T) } + Leaf ``` **`Map`** represents a tree with values stored in the branches. It is meant to be used as an efficient map data structure with integer keys and O(log n) read and write operations. -- **Node { value ~left ~right }**: Represents a map node with a `Maybe` and `left` and `right` subtrees. Empty nodes have `Maybe/None` stored in the `value` field, whislt non-empty nodes have `Maybe/Some` stored in the `value` field. +- **Node { value: Maybe(T), ~left: Map(T), ~right: Map(T) }**: Represents a map node with a `Maybe` and `left` and `right` subtrees. Empty nodes have `Maybe/None` stored in the `value` field, whilst non-empty nodes have `Maybe/Some` stored in the `value` field. - **Leaf**: Represents an unwritten, empty portion of the map. #### Syntax @@ -241,22 +241,19 @@ Retrieves a `value` from the `map` based on the `key`. Returns a tuple with the value and the `map` unchanged. ```rust -Map/get map key = - match map { - Map/Leaf: (*, map) - Map/Node: - switch _ = (== 0 key) { - 0: switch _ = (% key 2) { - 0: - let (got, rest) = (Map/get map.left (/ key 2)) - (got, (Map/Node map.value rest map.right)) - _: - let (got, rest) = (Map/get map.right (/ key 2)) - (got, (Map/Node map.value map.left rest)) - } - _: (map.value, map) - } - } +def Map/get (map: Map(T), key: u24) -> (T, Map(T)): + match map: + case Map/Leaf: + return (unreachable(), map) + case Map/Node: + if (0 == key): + return (Maybe/unwrap(map.value), map) + elif (key % 2 == 0): + (got, rest) = Map/get(map.left, (key / 2)) + return(got, Map/Node(map.value, rest, map.right)) + else: + (got, rest) = Map/get(map.right, (key / 2)) + return(got, Map/Node(map.value, map.left, rest)) ``` #### Syntax @@ -281,29 +278,23 @@ And the value resultant from the get function would be: ### Map/set -Sets a `value` in the `map` at the specified `key`. -Returns the map with the new value. - ```rust -Map/set map key value = - match map { - Map/Node: - switch _ = (== 0 key) { - 0: switch _ = (% key 2) { - 0: (Map/Node map.value (Map/set map.left (/ key 2) value) map.right) - _: (Map/Node map.value map.left (Map/set map.right (/ key 2) value)) - } - _: (Map/Node value map.left map.right) - } - Map/Leaf: - switch _ = (== 0 key) { - 0: switch _ = (% key 2) { - 0: (Map/Node * (Map/set Map/Leaf (/ key 2) value) Map/Leaf) - _: (Map/Node * Map/Leaf (Map/set Map/Leaf (/ key 2) value)) - } - _: (Map/Node value Map/Leaf Map/Leaf) - } - } +def Map/set (map: Map(T), key: u24, value: T) -> Map(T): + match map: + case Map/Node: + if (0 == key): + return Map/Node(Maybe/Some(value), map.left, map.right) + elif ((key % 2) == 0): + return Map/Node(map.value, Map/set(map.left, (key / 2), value), map.right) + else: + return Map/Node(map.value, map.left, Map/set(map.right, (key / 2), value)) + case Map/Leaf: + if (0 == key): + return Map/Node(Maybe/Some(value), Map/Leaf, Map/Leaf) + elif ((key % 2) == 0): + return Map/Node(Maybe/None, Map/set(Map/Leaf, (key / 2), value), Map/Leaf) + else: + return Map/Node(Maybe/None, Map/Leaf, Map/set(Map/Leaf, (key / 2),value)) ``` #### Syntax @@ -344,17 +335,17 @@ Applies a function to a value in the map. Returns the map with the value mapped. ```rust -Map/map (Map/Leaf) key f = Map/Leaf -Map/map (Map/Node value left right) key f = - switch _ = (== 0 key) { - 0: switch _ = (% key 2) { - 0: - (Map/Node value (Map/map left (/ key 2) f) right) - _: - (Map/Node value left (Map/map right (/ key 2) f)) - } - _: (Map/Node (f value) left right) - } +def Map/map (map: Map(T), key: u24, f: T -> T) -> Map(T): + match map: + case Map/Leaf: + return Map/Leaf + case Map/Node: + if (0 == key): + return Map/Node(Maybe/Some(f(Maybe/unwrap(map.value))), map.left, map.right) + elif ((key % 2) == 0): + return Map/Node(map.value, Map/map(map.left, (key / 2), f), map.right) + else: + return Map/Node(map.value, map.left, Map/map(map.right, (key / 2), f)) ``` #### Syntax @@ -366,6 +357,40 @@ x[0] @= lambda y: String/concat(y, " and mapped") # x[0] now contains "swapped and mapped" ``` + +### Map/contains +Checks if a `map` contains a given `key` and returns 0 or 1 as a `u24` number and the `map` unchanged. +```python +def Map/contains (map: Map(T), key: u24) -> (u24, Map(T)): + match map: + case Map/Leaf: + return (0, map) + case Map/Node: + if (0 == key): + match map.value: + case Maybe/Some: + return (1, map) + case Maybe/None: + return (0, map) + elif ((key % 2) == 0): + (new_value, new_map) = Map/contains(map.left, (key / 2)) + return (new_value, Map/Node(map.value, new_map, map.right)) + else: + (new_value, new_map) = Map/contains(map.right, (key / 2)) + return (new_value, Map/Node(map.value, map.left, new_map)) +``` + +#### Syntax + +With the same map that we `set` in the previous section, we can call the function `Map/contains` explicitly: + +```python +(num, map) = Map/contains(m, key) +return num +``` +Whilst the `num` variable will contain 0 or 1 depending on if the key is in the map or not. + + ## Nat ```python diff --git a/examples/example_fun.bend b/examples/example_fun.bend index dbac0765..8d701be0 100644 --- a/examples/example_fun.bend +++ b/examples/example_fun.bend @@ -45,6 +45,7 @@ bad_nums : Any = (+ id 1) # Write new data types like this type Option = (Some val) | None type Bool = True | False + # You can have pattern matching on definitions # Use `*` to ignore a pattern (Option.unwrap_or (Option/Some val) *) = val diff --git a/src/fun/builtins.bend b/src/fun/builtins.bend index 1057308d..8b188bef 100644 --- a/src/fun/builtins.bend +++ b/src/fun/builtins.bend @@ -187,7 +187,7 @@ def Maybe/unwrap(m: Maybe(T)) -> T: # MAP Impl type Map(T): - Node { value: Maybe(T), ~left: Map(T), ~right: Map(T)} + Node { value: Maybe(T), ~left: Map(T), ~right: Map(T) } Leaf # Creates an empty Map diff --git a/tests/golden_tests/prelude/applies_function_to_map.bend b/tests/golden_tests/prelude/applies_function_to_map.bend index 54755588..f069205d 100644 --- a/tests/golden_tests/prelude/applies_function_to_map.bend +++ b/tests/golden_tests/prelude/applies_function_to_map.bend @@ -1,13 +1,14 @@ # Checks if a generic map contains a given key, and if it does, applies a function to the value, otherwise it returns the map -def test(m: Map(u24), key: u24) -> Map(u24): +def test(m: Map(u24), key: u24) -> u24: def addtwo (x: u24) -> u24: return (x + 2) (num, map) = Map/contains(m, key) if (num == 0): - return m + return unreachable() else: - return Map/map(m, key, addtwo()) - + m = Map/map(m, key, addtwo()) + (value, map) = Map/get(m, key) + return value def main() -> _: m = {3: 255} return test(m, 3) diff --git a/tests/golden_tests/prelude/get_values_from_map.bend b/tests/golden_tests/prelude/get_values_from_map.bend index 8f44d9e6..8694e550 100644 --- a/tests/golden_tests/prelude/get_values_from_map.bend +++ b/tests/golden_tests/prelude/get_values_from_map.bend @@ -1,9 +1,9 @@ -def test1() -> (u24, Map(u24)): +def test1() -> (u24): m = {} m = Map/set(Map/set(Map/set(Map/empty, 3, 4), 2, 3), 1, 2) - (val, map) = Map/get(m, 1) - return Map/get(map, val) - + (val1, map1) = Map/get(m, 1) + (val2, map2) = Map/get(map1, val1) + return val2 def main() -> _: return test1() diff --git a/tests/golden_tests/prelude/map_checked_test.bend b/tests/golden_tests/prelude/map_checked_test.bend index 68849353..fa522b29 100644 --- a/tests/golden_tests/prelude/map_checked_test.bend +++ b/tests/golden_tests/prelude/map_checked_test.bend @@ -1,4 +1,5 @@ +#Tests the get_check function def main() -> _: - m1 = {0: 42, 1: 7, 2: 13, 3: 255, 4: 100} + m1 = {0: 1, 3: 2} return Map/get_check(m1, 3) diff --git a/tests/golden_tests/prelude/map_contains_test.bend b/tests/golden_tests/prelude/map_contains_test.bend index 6c2c227e..ca8c6abf 100644 --- a/tests/golden_tests/prelude/map_contains_test.bend +++ b/tests/golden_tests/prelude/map_contains_test.bend @@ -1,3 +1,3 @@ def main() -> _: - m1 = {0: 42, 1: 7, 2: 13, 3: 255, 4: 100} + m1 = {0: 23} return Map/contains(m1, 3) diff --git a/tests/snapshots/prelude__applies_function_to_map.bend.snap b/tests/snapshots/prelude__applies_function_to_map.bend.snap index a279ced9..e13e58b5 100644 --- a/tests/snapshots/prelude__applies_function_to_map.bend.snap +++ b/tests/snapshots/prelude__applies_function_to_map.bend.snap @@ -3,4 +3,4 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/prelude/applies_function_to_map.bend --- Strict mode: -λa (a Map/Node/tag Maybe/None Map/Leaf λb (b Map/Node/tag Maybe/None Map/Leaf λc (c Map/Node/tag λd (d Maybe/Some/tag 257) Map/Leaf Map/Leaf))) +257 diff --git a/tests/snapshots/prelude__builtin_Map_tests.bend.snap b/tests/snapshots/prelude__builtin_Map_tests.bend.snap deleted file mode 100644 index ce31d0b7..00000000 --- a/tests/snapshots/prelude__builtin_Map_tests.bend.snap +++ /dev/null @@ -1,6 +0,0 @@ ---- -source: tests/golden_tests.rs -input_file: tests/golden_tests/prelude/builtin_Map_tests.bend ---- -Strict mode: -((1, 3), (Map/Leaf, (λa (a Map/Node/tag λb (b Maybe/Some/tag 42) λc (c Map/Node/tag Maybe/None λd (d Map/Node/tag Maybe/None Map/Leaf λe (e Map/Node/tag λf (f Maybe/Some/tag 100) Map/Leaf Map/Leaf)) λg (g Map/Node/tag λh (h Maybe/Some/tag 13) Map/Leaf Map/Leaf)) λi (i Map/Node/tag λj (j Maybe/Some/tag 7) Map/Leaf λk (k Map/Node/tag λl (l Maybe/Some/tag 255) Map/Leaf Map/Leaf))), (Bool/False, (λm (m Map/Node/tag λn (n Maybe/Some/tag Nat/Zero) λo (o Map/Node/tag Maybe/None Map/Leaf λp (p Map/Node/tag λq (q Maybe/Some/tag λr (r Nat/Succ/tag λs (s Nat/Succ/tag Nat/Zero))) Map/Leaf Map/Leaf)) λt (t Map/Node/tag λu (u Maybe/Some/tag λv (v Nat/Succ/tag Nat/Zero)) Map/Leaf λw (w Map/Node/tag λx (x Maybe/Some/tag λy (y Nat/Succ/tag λz (z Nat/Succ/tag λab (ab Nat/Succ/tag Nat/Zero)))) Map/Leaf Map/Leaf))), (λbb (bb Map/Node/tag λcb (cb Maybe/Some/tag 42) λdb (db Map/Node/tag Maybe/None λeb (eb Map/Node/tag Maybe/None Map/Leaf λfb (fb Map/Node/tag λgb (gb Maybe/Some/tag λhb (hb 3)) Map/Leaf Map/Leaf)) λib (ib Map/Node/tag λjb (jb Maybe/Some/tag λkb (kb Nat/Succ/tag Nat/Zero)) Map/Leaf Map/Leaf)) λlb (lb Map/Node/tag λmb (mb Maybe/Some/tag Bool/True) λnb (nb Map/Node/tag Maybe/None Map/Leaf λob (ob Map/Node/tag λpb (pb Maybe/Some/tag Nat/Zero) Map/Leaf Map/Leaf)) λqb (qb Map/Node/tag λrb (rb Maybe/Some/tag 255) Map/Leaf Map/Leaf))), (λsb (sb Map/Node/tag Maybe/None λtb (tb Map/Node/tag Maybe/None Map/Leaf λub (ub Map/Node/tag λvb (vb Maybe/Some/tag 13) Map/Leaf Map/Leaf)) λwb (wb Map/Node/tag Maybe/None λxb (xb Map/Node/tag Maybe/None λyb (yb Map/Node/tag Maybe/None Map/Leaf λzb (zb Map/Node/tag λac (ac Maybe/Some/tag 144) Map/Leaf Map/Leaf)) λbc (bc Map/Node/tag λcc (cc Maybe/Some/tag 77) Map/Leaf Map/Leaf)) λdc (dc Map/Node/tag λec (ec Maybe/Some/tag 42) λfc (fc Map/Node/tag Maybe/None Map/Leaf λgc (gc Map/Node/tag λhc (hc Maybe/Some/tag 255) Map/Leaf Map/Leaf)) λic (ic Map/Node/tag λjc (jc Maybe/Some/tag 100) Map/Leaf Map/Leaf)))), λkc (kc Map/Node/tag λlc (lc Maybe/Some/tag 1) λmc (mc Map/Node/tag Maybe/None λnc (nc Map/Node/tag Maybe/None λoc (oc Map/Node/tag Maybe/None Map/Leaf λpc (pc Map/Node/tag λqc (qc Maybe/Some/tag 66) Map/Leaf Map/Leaf)) λrc (rc Map/Node/tag λsc (sc Maybe/Some/tag 36) Map/Leaf Map/Leaf)) λtc (tc Map/Node/tag λuc (uc Maybe/Some/tag 9) Map/Leaf Map/Leaf)) λvc (vc Map/Node/tag λwc (wc Maybe/Some/tag 4) λxc (xc Map/Node/tag Maybe/None Map/Leaf λyc (yc Map/Node/tag λzc (zc Maybe/Some/tag 25) Map/Leaf Map/Leaf)) λad (ad Map/Node/tag λbd (bd Maybe/Some/tag 16) Map/Leaf λcd (cd Map/Node/tag λdd (dd Maybe/Some/tag 49) Map/Leaf Map/Leaf))))))))))) diff --git a/tests/snapshots/prelude__get_values_from_map.bend.snap b/tests/snapshots/prelude__get_values_from_map.bend.snap index 166d4279..bfb008ea 100644 --- a/tests/snapshots/prelude__get_values_from_map.bend.snap +++ b/tests/snapshots/prelude__get_values_from_map.bend.snap @@ -3,4 +3,4 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/prelude/get_values_from_map.bend --- Strict mode: -(3, λa (a Map/Node/tag Maybe/None λb (b Map/Node/tag Maybe/None Map/Leaf λc (c Map/Node/tag λd (d Maybe/Some/tag 3) Map/Leaf Map/Leaf)) λe (e Map/Node/tag λf (f Maybe/Some/tag 2) Map/Leaf λg (g Map/Node/tag λh (h Maybe/Some/tag 4) Map/Leaf Map/Leaf)))) +3 diff --git a/tests/snapshots/prelude__map_checked_test.bend.snap b/tests/snapshots/prelude__map_checked_test.bend.snap index 654f3fc9..c968bc11 100644 --- a/tests/snapshots/prelude__map_checked_test.bend.snap +++ b/tests/snapshots/prelude__map_checked_test.bend.snap @@ -3,4 +3,4 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/prelude/map_checked_test.bend --- Strict mode: -(λa (a Maybe/Some/tag 255), λb (b Map/Node/tag λc (c Maybe/Some/tag 42) λd (d Map/Node/tag Maybe/None λe (e Map/Node/tag Maybe/None Map/Leaf λf (f Map/Node/tag λg (g Maybe/Some/tag 100) Map/Leaf Map/Leaf)) λh (h Map/Node/tag λi (i Maybe/Some/tag 13) Map/Leaf Map/Leaf)) λj (j Map/Node/tag λk (k Maybe/Some/tag 7) Map/Leaf λl (l Map/Node/tag λm (m Maybe/Some/tag 255) Map/Leaf Map/Leaf)))) +(λa (a Maybe/Some/tag 2), λb (b Map/Node/tag λc (c Maybe/Some/tag 1) Map/Leaf λd (d Map/Node/tag Maybe/None Map/Leaf λe (e Map/Node/tag λf (f Maybe/Some/tag 2) Map/Leaf Map/Leaf)))) diff --git a/tests/snapshots/prelude__map_contains_test.bend.snap b/tests/snapshots/prelude__map_contains_test.bend.snap index acaf0927..8036e853 100644 --- a/tests/snapshots/prelude__map_contains_test.bend.snap +++ b/tests/snapshots/prelude__map_contains_test.bend.snap @@ -3,4 +3,4 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/prelude/map_contains_test.bend --- Strict mode: -(1, λa (a Map/Node/tag λb (b Maybe/Some/tag 42) λc (c Map/Node/tag Maybe/None λd (d Map/Node/tag Maybe/None Map/Leaf λe (e Map/Node/tag λf (f Maybe/Some/tag 100) Map/Leaf Map/Leaf)) λg (g Map/Node/tag λh (h Maybe/Some/tag 13) Map/Leaf Map/Leaf)) λi (i Map/Node/tag λj (j Maybe/Some/tag 7) Map/Leaf λk (k Map/Node/tag λl (l Maybe/Some/tag 255) Map/Leaf Map/Leaf)))) +(0, λa (a Map/Node/tag λb (b Maybe/Some/tag 23) Map/Leaf Map/Leaf))