From ab2b9a982ede817362072623ff9ae2aa42e083da Mon Sep 17 00:00:00 2001 From: Louis Pilfold Date: Thu, 18 Jan 2024 20:34:43 +0000 Subject: Move recursion lessons together --- .../lesson05_list_recursion/code.gleam | 13 ------------ .../lesson05_list_recursion/text.html | 22 --------------------- .../lesson05_recursion/code.gleam | 17 ++++++++++++++++ .../lesson05_recursion/text.html | 20 +++++++++++++++++++ .../lesson06_multiple_subjects/code.gleam | 17 ---------------- .../lesson06_multiple_subjects/text.html | 13 ------------ .../lesson06_tail_calls/code.gleam | 21 ++++++++++++++++++++ .../lesson06_tail_calls/text.html | 23 ++++++++++++++++++++++ .../lesson07_alternative_patterns/code.gleam | 14 ------------- .../lesson07_alternative_patterns/text.html | 17 ---------------- .../lesson07_list_recursion/code.gleam | 13 ++++++++++++ .../lesson07_list_recursion/text.html | 22 +++++++++++++++++++++ .../lesson08_multiple_subjects/code.gleam | 17 ++++++++++++++++ .../lesson08_multiple_subjects/text.html | 13 ++++++++++++ .../lesson08_pattern_aliases/code.gleam | 15 -------------- .../lesson08_pattern_aliases/text.html | 7 ------- .../lesson09_alternative_patterns/code.gleam | 14 +++++++++++++ .../lesson09_alternative_patterns/text.html | 17 ++++++++++++++++ .../lesson09_guards/code.gleam | 15 -------------- .../lesson09_guards/text.html | 9 --------- .../lesson10_pattern_aliases/code.gleam | 15 ++++++++++++++ .../lesson10_pattern_aliases/text.html | 7 +++++++ .../lesson11_guards/code.gleam | 15 ++++++++++++++ .../lesson11_guards/text.html | 9 +++++++++ 24 files changed, 223 insertions(+), 142 deletions(-) delete mode 100644 src/content/chapter2_flow_control/lesson05_list_recursion/code.gleam delete mode 100644 src/content/chapter2_flow_control/lesson05_list_recursion/text.html create mode 100644 src/content/chapter2_flow_control/lesson05_recursion/code.gleam create mode 100644 src/content/chapter2_flow_control/lesson05_recursion/text.html delete mode 100644 src/content/chapter2_flow_control/lesson06_multiple_subjects/code.gleam delete mode 100644 src/content/chapter2_flow_control/lesson06_multiple_subjects/text.html create mode 100644 src/content/chapter2_flow_control/lesson06_tail_calls/code.gleam create mode 100644 src/content/chapter2_flow_control/lesson06_tail_calls/text.html delete mode 100644 src/content/chapter2_flow_control/lesson07_alternative_patterns/code.gleam delete mode 100644 src/content/chapter2_flow_control/lesson07_alternative_patterns/text.html create mode 100644 src/content/chapter2_flow_control/lesson07_list_recursion/code.gleam create mode 100644 src/content/chapter2_flow_control/lesson07_list_recursion/text.html create mode 100644 src/content/chapter2_flow_control/lesson08_multiple_subjects/code.gleam create mode 100644 src/content/chapter2_flow_control/lesson08_multiple_subjects/text.html delete mode 100644 src/content/chapter2_flow_control/lesson08_pattern_aliases/code.gleam delete mode 100644 src/content/chapter2_flow_control/lesson08_pattern_aliases/text.html create mode 100644 src/content/chapter2_flow_control/lesson09_alternative_patterns/code.gleam create mode 100644 src/content/chapter2_flow_control/lesson09_alternative_patterns/text.html delete mode 100644 src/content/chapter2_flow_control/lesson09_guards/code.gleam delete mode 100644 src/content/chapter2_flow_control/lesson09_guards/text.html create mode 100644 src/content/chapter2_flow_control/lesson10_pattern_aliases/code.gleam create mode 100644 src/content/chapter2_flow_control/lesson10_pattern_aliases/text.html create mode 100644 src/content/chapter2_flow_control/lesson11_guards/code.gleam create mode 100644 src/content/chapter2_flow_control/lesson11_guards/text.html (limited to 'src/content/chapter2_flow_control') diff --git a/src/content/chapter2_flow_control/lesson05_list_recursion/code.gleam b/src/content/chapter2_flow_control/lesson05_list_recursion/code.gleam deleted file mode 100644 index 370675a..0000000 --- a/src/content/chapter2_flow_control/lesson05_list_recursion/code.gleam +++ /dev/null @@ -1,13 +0,0 @@ -import gleam/io - -pub fn main() { - let sum = sum_list([18, 56, 35, 85, 91], 0) - io.debug(sum) -} - -fn sum_list(list: List(Int), total: Int) -> Int { - case list { - [first, ..rest] -> sum_list(rest, total + first) - [] -> total - } -} diff --git a/src/content/chapter2_flow_control/lesson05_list_recursion/text.html b/src/content/chapter2_flow_control/lesson05_list_recursion/text.html deleted file mode 100644 index 7f2351d..0000000 --- a/src/content/chapter2_flow_control/lesson05_list_recursion/text.html +++ /dev/null @@ -1,22 +0,0 @@ -

- Most commonly functions in the - gleam/list - module are used to iterate across a list, but at times you may prefer - to work with the list directly. -

-

- Gleam doesn't have a looping syntax, instead iteration is done through - recursion and pattern matching. -

-

- The [first, ..rest] pattern matches on a list with at least one - element, assigning the first element to the variable first and - the rest of the list to the variable rest. - By using this pattern and a pattern for the empty list [] a - function can run code on each element of a list until the end is reached. -

-

- This code sums a list by recursing over the list and adding each int to a - total argument, returning it when the end is reached. -

- diff --git a/src/content/chapter2_flow_control/lesson05_recursion/code.gleam b/src/content/chapter2_flow_control/lesson05_recursion/code.gleam new file mode 100644 index 0000000..ee93a6f --- /dev/null +++ b/src/content/chapter2_flow_control/lesson05_recursion/code.gleam @@ -0,0 +1,17 @@ +import gleam/io + +pub fn main() { + io.debug(factorial(5)) + io.debug(factorial(7)) +} + +// A recursive functions that calculates factorial +pub fn factorial(x: Int) -> Int { + case x { + // Base case + 1 -> 1 + + // Recursive case + _ -> x * factorial(x - 1) + } +} diff --git a/src/content/chapter2_flow_control/lesson05_recursion/text.html b/src/content/chapter2_flow_control/lesson05_recursion/text.html new file mode 100644 index 0000000..f1585bb --- /dev/null +++ b/src/content/chapter2_flow_control/lesson05_recursion/text.html @@ -0,0 +1,20 @@ +

+ Gleam doesn't have loops, instead iteration is done through recursion, that is + through top-level functions calling themselves with different arguments. +

+

+ A recursive function needs to have at least one base case and at + least one recursive case. A base case returns a value without calling + the function again. A recursive case calls the function again with different + inputs, looping again. +

+

+ The Gleam standard library has functions for various common looping patterns, + some of which will be introduced in later lessons, however for more complex + loops manual recursion is often the clearest way to write it. +

+

+ Recursion can seem daunting or unclear at first if you are more familiar with + languages that have special looping features, but stick with it! With time + it'll become just as familiar and comfortable as any other way of iterating. +

diff --git a/src/content/chapter2_flow_control/lesson06_multiple_subjects/code.gleam b/src/content/chapter2_flow_control/lesson06_multiple_subjects/code.gleam deleted file mode 100644 index d7aa34a..0000000 --- a/src/content/chapter2_flow_control/lesson06_multiple_subjects/code.gleam +++ /dev/null @@ -1,17 +0,0 @@ -import gleam/io -import gleam/int - -pub fn main() { - let x = int.random(2) - let y = int.random(2) - io.debug(x) - io.debug(y) - - let result = case x, y { - 0, 0 -> "Both are zero" - 0, _ -> "First is zero" - _, 0 -> "Second is zero" - _, _ -> "Neither are zero" - } - io.debug(result) -} diff --git a/src/content/chapter2_flow_control/lesson06_multiple_subjects/text.html b/src/content/chapter2_flow_control/lesson06_multiple_subjects/text.html deleted file mode 100644 index 26a7ea3..0000000 --- a/src/content/chapter2_flow_control/lesson06_multiple_subjects/text.html +++ /dev/null @@ -1,13 +0,0 @@ -

- Sometimes it is useful to pattern match on multiple values at the same time in - one case experession. -

-

- To do this you can give multiple subjects and multiple patterns, separated - commas. -

-

- When matching on multiple subjects there must be the same number of patterns - as there are subjects. Try removing one of the _, sub-patterns to - see the compile time error that is returned. -

diff --git a/src/content/chapter2_flow_control/lesson06_tail_calls/code.gleam b/src/content/chapter2_flow_control/lesson06_tail_calls/code.gleam new file mode 100644 index 0000000..d823eec --- /dev/null +++ b/src/content/chapter2_flow_control/lesson06_tail_calls/code.gleam @@ -0,0 +1,21 @@ +import gleam/io + +pub fn main() { + io.debug(factorial(5)) + io.debug(factorial(7)) +} + +pub fn factorial(x: Int) -> Int { + // The public function calls the private tail recursive function + factorial_loop(x, 1) +} + +fn factorial_loop(x: Int, accumulator: Int) -> Int { + case x { + 1 -> accumulator + + // The last thing this function does is call itself + // In the previous lesson the last thing it did was multiple two ints + _ -> factorial_loop(x - 1, accumulator * x) + } +} diff --git a/src/content/chapter2_flow_control/lesson06_tail_calls/text.html b/src/content/chapter2_flow_control/lesson06_tail_calls/text.html new file mode 100644 index 0000000..ec39cda --- /dev/null +++ b/src/content/chapter2_flow_control/lesson06_tail_calls/text.html @@ -0,0 +1,23 @@ +

+ When a function is called a new stack frame is created in memory to store the + arguments and local variables of the function. If lots of these frames are + created during recursion then the program would use a large amount of memory, + or even crash the program if some limit is hit. +

+

+ To avoid this problem Gleam supports tail call optimisation, which + allows the compiler to reuse the stack frame for the current function if a + function call is the last thing the function does, removing the memory cost. +

+ +

+ Unoptimised recursive functions can often be rewritten into tail call + optimised functions by using an accumulator. An accumulator is a variable that + is passed along in addition to the data, similar to a mutable variable in a + language with while loops. +

+

+ Accumulators should be hidden away from the users of your code, they are + internal implementation details. To do this write a public function that calls + a recursive private function with the initial accumulator value. +

diff --git a/src/content/chapter2_flow_control/lesson07_alternative_patterns/code.gleam b/src/content/chapter2_flow_control/lesson07_alternative_patterns/code.gleam deleted file mode 100644 index 06a6562..0000000 --- a/src/content/chapter2_flow_control/lesson07_alternative_patterns/code.gleam +++ /dev/null @@ -1,14 +0,0 @@ -import gleam/io -import gleam/int - -pub fn main() { - let number = int.random(10) - io.debug(number) - - let result = case number { - 2 | 4 | 6 | 8 -> "This is an even number" - 1 | 3 | 5 | 7 -> "This is an odd number" - _ -> "I'm not sure" - } - io.debug(result) -} diff --git a/src/content/chapter2_flow_control/lesson07_alternative_patterns/text.html b/src/content/chapter2_flow_control/lesson07_alternative_patterns/text.html deleted file mode 100644 index 10ad731..0000000 --- a/src/content/chapter2_flow_control/lesson07_alternative_patterns/text.html +++ /dev/null @@ -1,17 +0,0 @@ -

- Alternative patterns can be given for a case clause using the - | operator. If any of the patterns match then the clause matches. -

-

- When matching on multiple subjects there must be the same number of patterns - as there are subjects. Try removing one of the _, sub-patterns to - see the compile time error that is returned. -

-

- If a pattern defines a variable then all of the alternative patterns for that - clause must also define a variable with the same name and same type. -

-

- Currently it is not possible to have nested alternative patterns, so the - pattern [1 | 2 | 3] is not valid. -

diff --git a/src/content/chapter2_flow_control/lesson07_list_recursion/code.gleam b/src/content/chapter2_flow_control/lesson07_list_recursion/code.gleam new file mode 100644 index 0000000..370675a --- /dev/null +++ b/src/content/chapter2_flow_control/lesson07_list_recursion/code.gleam @@ -0,0 +1,13 @@ +import gleam/io + +pub fn main() { + let sum = sum_list([18, 56, 35, 85, 91], 0) + io.debug(sum) +} + +fn sum_list(list: List(Int), total: Int) -> Int { + case list { + [first, ..rest] -> sum_list(rest, total + first) + [] -> total + } +} diff --git a/src/content/chapter2_flow_control/lesson07_list_recursion/text.html b/src/content/chapter2_flow_control/lesson07_list_recursion/text.html new file mode 100644 index 0000000..7f2351d --- /dev/null +++ b/src/content/chapter2_flow_control/lesson07_list_recursion/text.html @@ -0,0 +1,22 @@ +

+ Most commonly functions in the + gleam/list + module are used to iterate across a list, but at times you may prefer + to work with the list directly. +

+

+ Gleam doesn't have a looping syntax, instead iteration is done through + recursion and pattern matching. +

+

+ The [first, ..rest] pattern matches on a list with at least one + element, assigning the first element to the variable first and + the rest of the list to the variable rest. + By using this pattern and a pattern for the empty list [] a + function can run code on each element of a list until the end is reached. +

+

+ This code sums a list by recursing over the list and adding each int to a + total argument, returning it when the end is reached. +

+ diff --git a/src/content/chapter2_flow_control/lesson08_multiple_subjects/code.gleam b/src/content/chapter2_flow_control/lesson08_multiple_subjects/code.gleam new file mode 100644 index 0000000..d7aa34a --- /dev/null +++ b/src/content/chapter2_flow_control/lesson08_multiple_subjects/code.gleam @@ -0,0 +1,17 @@ +import gleam/io +import gleam/int + +pub fn main() { + let x = int.random(2) + let y = int.random(2) + io.debug(x) + io.debug(y) + + let result = case x, y { + 0, 0 -> "Both are zero" + 0, _ -> "First is zero" + _, 0 -> "Second is zero" + _, _ -> "Neither are zero" + } + io.debug(result) +} diff --git a/src/content/chapter2_flow_control/lesson08_multiple_subjects/text.html b/src/content/chapter2_flow_control/lesson08_multiple_subjects/text.html new file mode 100644 index 0000000..26a7ea3 --- /dev/null +++ b/src/content/chapter2_flow_control/lesson08_multiple_subjects/text.html @@ -0,0 +1,13 @@ +

+ Sometimes it is useful to pattern match on multiple values at the same time in + one case experession. +

+

+ To do this you can give multiple subjects and multiple patterns, separated + commas. +

+

+ When matching on multiple subjects there must be the same number of patterns + as there are subjects. Try removing one of the _, sub-patterns to + see the compile time error that is returned. +

diff --git a/src/content/chapter2_flow_control/lesson08_pattern_aliases/code.gleam b/src/content/chapter2_flow_control/lesson08_pattern_aliases/code.gleam deleted file mode 100644 index ee40a26..0000000 --- a/src/content/chapter2_flow_control/lesson08_pattern_aliases/code.gleam +++ /dev/null @@ -1,15 +0,0 @@ -import gleam/io - -pub fn main() { - io.debug(get_first_non_empty([[], [1, 2, 3], [4, 5]])) - io.debug(get_first_non_empty([[1, 2], [3, 4, 5], []])) - io.debug(get_first_non_empty([[], [], []])) -} - -fn get_first_non_empty(lists: List(List(t))) -> List(t) { - case lists { - [[_, ..] as first, ..] -> first - [_, ..rest] -> get_first_non_empty(rest) - [] -> [] - } -} diff --git a/src/content/chapter2_flow_control/lesson08_pattern_aliases/text.html b/src/content/chapter2_flow_control/lesson08_pattern_aliases/text.html deleted file mode 100644 index b737eb8..0000000 --- a/src/content/chapter2_flow_control/lesson08_pattern_aliases/text.html +++ /dev/null @@ -1,7 +0,0 @@ -

- The as operator can be used to assign sub patterns to variables. -

-

- The pattern [_, ..] as it will match any non-empty list and - assign that list to the variable it. -

diff --git a/src/content/chapter2_flow_control/lesson09_alternative_patterns/code.gleam b/src/content/chapter2_flow_control/lesson09_alternative_patterns/code.gleam new file mode 100644 index 0000000..06a6562 --- /dev/null +++ b/src/content/chapter2_flow_control/lesson09_alternative_patterns/code.gleam @@ -0,0 +1,14 @@ +import gleam/io +import gleam/int + +pub fn main() { + let number = int.random(10) + io.debug(number) + + let result = case number { + 2 | 4 | 6 | 8 -> "This is an even number" + 1 | 3 | 5 | 7 -> "This is an odd number" + _ -> "I'm not sure" + } + io.debug(result) +} diff --git a/src/content/chapter2_flow_control/lesson09_alternative_patterns/text.html b/src/content/chapter2_flow_control/lesson09_alternative_patterns/text.html new file mode 100644 index 0000000..10ad731 --- /dev/null +++ b/src/content/chapter2_flow_control/lesson09_alternative_patterns/text.html @@ -0,0 +1,17 @@ +

+ Alternative patterns can be given for a case clause using the + | operator. If any of the patterns match then the clause matches. +

+

+ When matching on multiple subjects there must be the same number of patterns + as there are subjects. Try removing one of the _, sub-patterns to + see the compile time error that is returned. +

+

+ If a pattern defines a variable then all of the alternative patterns for that + clause must also define a variable with the same name and same type. +

+

+ Currently it is not possible to have nested alternative patterns, so the + pattern [1 | 2 | 3] is not valid. +

diff --git a/src/content/chapter2_flow_control/lesson09_guards/code.gleam b/src/content/chapter2_flow_control/lesson09_guards/code.gleam deleted file mode 100644 index 3744228..0000000 --- a/src/content/chapter2_flow_control/lesson09_guards/code.gleam +++ /dev/null @@ -1,15 +0,0 @@ -import gleam/io - -pub fn main() { - let numbers = [1, 2, 3, 4, 5] - io.debug(get_first_larger(numbers, 3)) - io.debug(get_first_larger(numbers, 5)) -} - -fn get_first_larger(lists: List(Int), limit: Int) -> Int { - case lists { - [first, ..] if first > limit -> first - [_, ..rest] -> get_first_larger(rest, limit) - [] -> 0 - } -} diff --git a/src/content/chapter2_flow_control/lesson09_guards/text.html b/src/content/chapter2_flow_control/lesson09_guards/text.html deleted file mode 100644 index 3ea9cc5..0000000 --- a/src/content/chapter2_flow_control/lesson09_guards/text.html +++ /dev/null @@ -1,9 +0,0 @@ -

- The if keyword can be used with case expressions to add a - guard to a pattern. A guard is an expression that must evaluate to - True for the pattern to match. -

-

- Only a limited set of operators can be used in guards, and functions cannot be - called at all. -

diff --git a/src/content/chapter2_flow_control/lesson10_pattern_aliases/code.gleam b/src/content/chapter2_flow_control/lesson10_pattern_aliases/code.gleam new file mode 100644 index 0000000..ee40a26 --- /dev/null +++ b/src/content/chapter2_flow_control/lesson10_pattern_aliases/code.gleam @@ -0,0 +1,15 @@ +import gleam/io + +pub fn main() { + io.debug(get_first_non_empty([[], [1, 2, 3], [4, 5]])) + io.debug(get_first_non_empty([[1, 2], [3, 4, 5], []])) + io.debug(get_first_non_empty([[], [], []])) +} + +fn get_first_non_empty(lists: List(List(t))) -> List(t) { + case lists { + [[_, ..] as first, ..] -> first + [_, ..rest] -> get_first_non_empty(rest) + [] -> [] + } +} diff --git a/src/content/chapter2_flow_control/lesson10_pattern_aliases/text.html b/src/content/chapter2_flow_control/lesson10_pattern_aliases/text.html new file mode 100644 index 0000000..b737eb8 --- /dev/null +++ b/src/content/chapter2_flow_control/lesson10_pattern_aliases/text.html @@ -0,0 +1,7 @@ +

+ The as operator can be used to assign sub patterns to variables. +

+

+ The pattern [_, ..] as it will match any non-empty list and + assign that list to the variable it. +

diff --git a/src/content/chapter2_flow_control/lesson11_guards/code.gleam b/src/content/chapter2_flow_control/lesson11_guards/code.gleam new file mode 100644 index 0000000..3744228 --- /dev/null +++ b/src/content/chapter2_flow_control/lesson11_guards/code.gleam @@ -0,0 +1,15 @@ +import gleam/io + +pub fn main() { + let numbers = [1, 2, 3, 4, 5] + io.debug(get_first_larger(numbers, 3)) + io.debug(get_first_larger(numbers, 5)) +} + +fn get_first_larger(lists: List(Int), limit: Int) -> Int { + case lists { + [first, ..] if first > limit -> first + [_, ..rest] -> get_first_larger(rest, limit) + [] -> 0 + } +} diff --git a/src/content/chapter2_flow_control/lesson11_guards/text.html b/src/content/chapter2_flow_control/lesson11_guards/text.html new file mode 100644 index 0000000..3ea9cc5 --- /dev/null +++ b/src/content/chapter2_flow_control/lesson11_guards/text.html @@ -0,0 +1,9 @@ +

+ The if keyword can be used with case expressions to add a + guard to a pattern. A guard is an expression that must evaluate to + True for the pattern to match. +

+

+ Only a limited set of operators can be used in guards, and functions cannot be + called at all. +

-- cgit v1.2.3