From c4108abc348ae3eab77e7bcf408310c7a0e5524d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Por=C4=99ba?= Date: Sat, 6 Jan 2024 20:25:27 +0000 Subject: [PATCH 01/33] setting up the structure for leap approaches --- .../practice/leap/.approaches/case/content.md | 0 .../leap/.approaches/case/snippet.txt | 0 .../practice/leap/.approaches/cond/content.md | 0 .../leap/.approaches/cond/snippet.txt | 0 .../practice/leap/.approaches/config.json | 45 +++++++++++++++++++ .../leap/.approaches/guards/content.md | 0 .../leap/.approaches/guards/snippet.txt | 0 .../practice/leap/.approaches/introduction.md | 0 .../leap/.approaches/operators/content.md | 0 .../leap/.approaches/operators/snippet.txt | 0 10 files changed, 45 insertions(+) create mode 100644 exercises/practice/leap/.approaches/case/content.md create mode 100644 exercises/practice/leap/.approaches/case/snippet.txt create mode 100644 exercises/practice/leap/.approaches/cond/content.md create mode 100644 exercises/practice/leap/.approaches/cond/snippet.txt create mode 100644 exercises/practice/leap/.approaches/config.json create mode 100644 exercises/practice/leap/.approaches/guards/content.md create mode 100644 exercises/practice/leap/.approaches/guards/snippet.txt create mode 100644 exercises/practice/leap/.approaches/introduction.md create mode 100644 exercises/practice/leap/.approaches/operators/content.md create mode 100644 exercises/practice/leap/.approaches/operators/snippet.txt diff --git a/exercises/practice/leap/.approaches/case/content.md b/exercises/practice/leap/.approaches/case/content.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/exercises/practice/leap/.approaches/case/snippet.txt b/exercises/practice/leap/.approaches/case/snippet.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/exercises/practice/leap/.approaches/cond/content.md b/exercises/practice/leap/.approaches/cond/content.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/exercises/practice/leap/.approaches/cond/snippet.txt b/exercises/practice/leap/.approaches/cond/snippet.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/exercises/practice/leap/.approaches/config.json b/exercises/practice/leap/.approaches/config.json new file mode 100644 index 0000000000..570db6f148 --- /dev/null +++ b/exercises/practice/leap/.approaches/config.json @@ -0,0 +1,45 @@ +{ + "introduction": { + "authors": [ + "michalporeba" + ] + }, + "approaches": [ + { + "uuid": "be6d6c6e-8e19-4657-aad5-3382e7ec01db", + "slug": "operators", + "title": "Boolean Operators", + "blurb": "Use boolean operators to combine the checks.", + "authors": [ + "michalporeba" + ] + }, + { + "uuid": "0267853e-9607-4b60-b2f9-e4a34f5316db", + "slug": "guards", + "title": "Function Guards", + "blurb": "Use function guards to control order of checks.", + "authors": [ + "michalporeba" + ] + }, + { + "uuid": "428e3cee-309a-4c45-a6d4-3bff4eb41daa", + "slug": "cond", + "title": "Cond", + "blurb": "Use `cond` to control order of checks.", + "authors": [ + "michalporeba" + ] + }, + { + "uuid": "129e6863-275b-4fa3-abfe-4cb07c97acae", + "slug": "case", + "title": "Case", + "blurb": "Use `case` and tuples to decide if the year is a leap one.", + "authors": [ + "michalporeba" + ] + } + ] +} diff --git a/exercises/practice/leap/.approaches/guards/content.md b/exercises/practice/leap/.approaches/guards/content.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/exercises/practice/leap/.approaches/guards/snippet.txt b/exercises/practice/leap/.approaches/guards/snippet.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/exercises/practice/leap/.approaches/introduction.md b/exercises/practice/leap/.approaches/introduction.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/exercises/practice/leap/.approaches/operators/content.md b/exercises/practice/leap/.approaches/operators/content.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/exercises/practice/leap/.approaches/operators/snippet.txt b/exercises/practice/leap/.approaches/operators/snippet.txt new file mode 100644 index 0000000000..e69de29bb2 From 630a266c7b06ec5ac8042c2afca7a5a0a03cd41d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Por=C4=99ba?= Date: Sat, 6 Jan 2024 21:05:40 +0000 Subject: [PATCH 02/33] first draft of the introduction --- .../practice/leap/.approaches/introduction.md | 91 +++++++++++++++++++ 1 file changed, 91 insertions(+) diff --git a/exercises/practice/leap/.approaches/introduction.md b/exercises/practice/leap/.approaches/introduction.md index e69de29bb2..4563fe6463 100644 --- a/exercises/practice/leap/.approaches/introduction.md +++ b/exercises/practice/leap/.approaches/introduction.md @@ -0,0 +1,91 @@ +# Introduction + +Every fourth year is a leap year (with some exceptions), but let's consider this one condition first. + +To solve the Leap problem, we must determine if a year is evenly divisible by a number or if a reminder of an integer division is zero. +Such operation in computing is called [modulo][modulo]. + +Unlike many languages, Elixir does not have [operators][operators] for either integer division or modulo. +Instead, it provides [`rem/2`][rem] guard and the [`Integer.mod/2`][mod] function. + +The two functions differ in how they work with negative numbers, but since, in this exercise, +all the numbers are non-negative, both could work, depending on the approach. + +## General Solution + +To check if a year is divisible by `n`, we can do `rem(year, n) == 0`. + +Any approach to the problem will perform this check three times to check if a year is equally divisible by 4, 100 and 400. +What will differ is what Elixir features we will use to combine the checks. + +## Approach: Boolean Operators + +The full rules are as follows: +A year is a leap year if +* it is divisible by 4 +* but not divisible by 100 +* unless it is divisible by 400 + +We can use [boolean operators][boolean-operators] to combine the checks, for example, like so: + +```elixir +rem(year, 400) == 0 or (rem(year, 100) != 0) and rem(year, 4) == 0 +``` +In the [boolean operators appraoch][operators-approach] we discuss the details of the solution. +It includes variations of the operators and their precendence. + +## Approach: Function Guards + +Instead of using boolean operators, we can define multiple `leap_year?/1` functions with different guards. +We can use the order of the definitions to ensure correct check. + +```elixir +def leap_year?(year) when rem(year,400)==0, do: true +def leap_year?(year) when rem(year,100)==0, do: false +def leap_year?(year) when rem(year,4)==0, do: true +def leap_year?(_), do: false +``` + +In the [functions with guards approach][guards-approach] we discuss why in this approach the `Integer.mod/2` function will not work. + +## Approach: Using cond + +Similarly to the functions with guards, the order of the checks can be done inside a function with `cond` expression. + +```elixir +cond do + rem(year, 400) == 0 -> true + rem(year, 100) == 0 -> false + rem(year, 4) == 0 -> true + true -> false +end +``` + +We discuss this briefly in the [cond approach][cond-approach] + +## Approach: Using case + +Using `case` is yet another way to check for a leap year. This time, all the reminders are calculated and put into a tuple, and pattern matching is used to decide the outcome. + +```elixir +case { rem(year, 400), rem(year, 100), rem(year, 4) } do + { 0, _, _ } -> true + { _, 0, _ } -> false + { _, _, 0 } -> true + { _, _, _ } -> false +end +``` +In the [case approach][case-approach] we discuss the pattern matchin in a case expression. + + +[modulo]: https://en.wikipedia.org/wiki/Modulo +[operators]: https://hexdocs.pm/elixir/1.16.0/operators.html +[rem]: https://hexdocs.pm/elixir/1.16.0/Kernel.html#rem/2 +[mod]: https://hexdocs.pm/elixir/1.16.0/Integer.html#mod/2 +[boolean-operators]: https://hexdocs.pm/elixir/1.11.4/operators.html#general-operators +[operators-approach]: https://exercism.org/tracks/elixir/exercises/leap/approaches/operators +[guards-approach]: https://exercism.org/tracks/elixir/exercises/leap/approaches/guards +[cond-approach]: https://exercism.org/tracks/elixir/exercises/leap/approaches/cond +[case-approach]: https://exercism.org/tracks/elixir/exercises/leap/approaches/case + + From d4084e025a2a37381985e69bb8360f5559c87372 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Por=C4=99ba?= Date: Sat, 6 Jan 2024 21:31:35 +0000 Subject: [PATCH 03/33] adding myself to the exercise contributors --- exercises/practice/leap/.meta/config.json | 1 + 1 file changed, 1 insertion(+) diff --git a/exercises/practice/leap/.meta/config.json b/exercises/practice/leap/.meta/config.json index 6fd240246a..a914e88c1c 100644 --- a/exercises/practice/leap/.meta/config.json +++ b/exercises/practice/leap/.meta/config.json @@ -12,6 +12,7 @@ "korbin", "kytrinyx", "lpil", + "michalporeba", "neenjaw", "parkerl", "sotojuan", From 2b8ec4777001a25c01563aa5bba01e294d220388 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Por=C4=99ba?= Date: Sat, 6 Jan 2024 21:46:27 +0000 Subject: [PATCH 04/33] fixing formatting --- .../practice/leap/.approaches/introduction.md | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/exercises/practice/leap/.approaches/introduction.md b/exercises/practice/leap/.approaches/introduction.md index 4563fe6463..1331d57c9a 100644 --- a/exercises/practice/leap/.approaches/introduction.md +++ b/exercises/practice/leap/.approaches/introduction.md @@ -40,9 +40,9 @@ Instead of using boolean operators, we can define multiple `leap_year?/1` functi We can use the order of the definitions to ensure correct check. ```elixir -def leap_year?(year) when rem(year,400)==0, do: true -def leap_year?(year) when rem(year,100)==0, do: false -def leap_year?(year) when rem(year,4)==0, do: true +def leap_year?(year) when rem(year, 400) == 0, do: true +def leap_year?(year) when rem(year, 100) == 0, do: false +def leap_year?(year) when rem(year, 4) == 0, do: true def leap_year?(_), do: false ``` @@ -54,10 +54,10 @@ Similarly to the functions with guards, the order of the checks can be done insi ```elixir cond do - rem(year, 400) == 0 -> true + rem(year, 400) == 0 -> true rem(year, 100) == 0 -> false - rem(year, 4) == 0 -> true - true -> false + rem(year, 4) == 0 -> true + true -> false end ``` @@ -65,7 +65,8 @@ We discuss this briefly in the [cond approach][cond-approach] ## Approach: Using case -Using `case` is yet another way to check for a leap year. This time, all the reminders are calculated and put into a tuple, and pattern matching is used to decide the outcome. +Using `case` is yet another way to check for a leap year. +This time, all the reminders are calculated and put into a tuple, and pattern matching is used to decide the outcome. ```elixir case { rem(year, 400), rem(year, 100), rem(year, 4) } do From 616f6ec0b97bfe4ead49a38ece35c94196aa6c28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Por=C4=99ba?= Date: Sat, 6 Jan 2024 21:53:31 +0000 Subject: [PATCH 05/33] snippets and headers as placeholders --- exercises/practice/leap/.approaches/case/content.md | 1 + exercises/practice/leap/.approaches/case/snippet.txt | 8 ++++++++ exercises/practice/leap/.approaches/cond/content.md | 1 + exercises/practice/leap/.approaches/cond/snippet.txt | 8 ++++++++ exercises/practice/leap/.approaches/guards/content.md | 1 + exercises/practice/leap/.approaches/guards/snippet.txt | 4 ++++ exercises/practice/leap/.approaches/operators/content.md | 1 + exercises/practice/leap/.approaches/operators/snippet.txt | 5 +++++ 8 files changed, 29 insertions(+) diff --git a/exercises/practice/leap/.approaches/case/content.md b/exercises/practice/leap/.approaches/case/content.md index e69de29bb2..cba6194a61 100644 --- a/exercises/practice/leap/.approaches/case/content.md +++ b/exercises/practice/leap/.approaches/case/content.md @@ -0,0 +1 @@ +# Using `case` \ No newline at end of file diff --git a/exercises/practice/leap/.approaches/case/snippet.txt b/exercises/practice/leap/.approaches/case/snippet.txt index e69de29bb2..3e44884af3 100644 --- a/exercises/practice/leap/.approaches/case/snippet.txt +++ b/exercises/practice/leap/.approaches/case/snippet.txt @@ -0,0 +1,8 @@ +def leap_year?(year) do + case { rem(year, 400), rem(year, 100), rem(year, 4) } do + { 0, _, _ } -> true + { _, 0, _ } -> false + { _, _, 0 } -> true + { _, _, _ } -> false + end +end \ No newline at end of file diff --git a/exercises/practice/leap/.approaches/cond/content.md b/exercises/practice/leap/.approaches/cond/content.md index e69de29bb2..0c86112b86 100644 --- a/exercises/practice/leap/.approaches/cond/content.md +++ b/exercises/practice/leap/.approaches/cond/content.md @@ -0,0 +1 @@ +# Using `cond` \ No newline at end of file diff --git a/exercises/practice/leap/.approaches/cond/snippet.txt b/exercises/practice/leap/.approaches/cond/snippet.txt index e69de29bb2..1b8df2f6a8 100644 --- a/exercises/practice/leap/.approaches/cond/snippet.txt +++ b/exercises/practice/leap/.approaches/cond/snippet.txt @@ -0,0 +1,8 @@ +def leap_year?(year) do + cond do + rem(year, 400) == 0 -> true + rem(year, 100) == 0 -> false + rem(year, 4) == 0 -> true + true -> false + end +end \ No newline at end of file diff --git a/exercises/practice/leap/.approaches/guards/content.md b/exercises/practice/leap/.approaches/guards/content.md index e69de29bb2..cb94d6f0c6 100644 --- a/exercises/practice/leap/.approaches/guards/content.md +++ b/exercises/practice/leap/.approaches/guards/content.md @@ -0,0 +1 @@ +# Function Guards \ No newline at end of file diff --git a/exercises/practice/leap/.approaches/guards/snippet.txt b/exercises/practice/leap/.approaches/guards/snippet.txt index e69de29bb2..5880d5c450 100644 --- a/exercises/practice/leap/.approaches/guards/snippet.txt +++ b/exercises/practice/leap/.approaches/guards/snippet.txt @@ -0,0 +1,4 @@ +def leap_year?(year) when rem(year, 400) == 0, do: true +def leap_year?(year) when rem(year, 100) == 0, do: false +def leap_year?(year) when rem(year, 4) == 0, do: true +def leap_year?(_), do: false \ No newline at end of file diff --git a/exercises/practice/leap/.approaches/operators/content.md b/exercises/practice/leap/.approaches/operators/content.md index e69de29bb2..5a046b77a9 100644 --- a/exercises/practice/leap/.approaches/operators/content.md +++ b/exercises/practice/leap/.approaches/operators/content.md @@ -0,0 +1 @@ +# Boolean Operators \ No newline at end of file diff --git a/exercises/practice/leap/.approaches/operators/snippet.txt b/exercises/practice/leap/.approaches/operators/snippet.txt index e69de29bb2..69c218682b 100644 --- a/exercises/practice/leap/.approaches/operators/snippet.txt +++ b/exercises/practice/leap/.approaches/operators/snippet.txt @@ -0,0 +1,5 @@ +def leap_year?(year) do + rem(year, 400) == 0 + or (rem(year, 100) != 0) + and rem(year, 4) == 0 +end \ No newline at end of file From 0a4fddca0b1d5ce9898e7b5b708c8668537aff90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Por=C4=99ba?= Date: Sat, 6 Jan 2024 23:20:01 +0000 Subject: [PATCH 06/33] improving the code with divides? --- .../practice/leap/.approaches/cond/snippet.txt | 6 +++--- .../practice/leap/.approaches/introduction.md | 14 +++++++++----- .../leap/.approaches/operators/snippet.txt | 6 +++--- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/exercises/practice/leap/.approaches/cond/snippet.txt b/exercises/practice/leap/.approaches/cond/snippet.txt index 1b8df2f6a8..184be26376 100644 --- a/exercises/practice/leap/.approaches/cond/snippet.txt +++ b/exercises/practice/leap/.approaches/cond/snippet.txt @@ -1,8 +1,8 @@ def leap_year?(year) do cond do - rem(year, 400) == 0 -> true - rem(year, 100) == 0 -> false - rem(year, 4) == 0 -> true + divides?(year, 400) -> true + divides?(year, 100) -> false + divides?(year, 4) -> true true -> false end end \ No newline at end of file diff --git a/exercises/practice/leap/.approaches/introduction.md b/exercises/practice/leap/.approaches/introduction.md index 1331d57c9a..7bb7e5a8c3 100644 --- a/exercises/practice/leap/.approaches/introduction.md +++ b/exercises/practice/leap/.approaches/introduction.md @@ -13,7 +13,11 @@ all the numbers are non-negative, both could work, depending on the approach. ## General Solution -To check if a year is divisible by `n`, we can do `rem(year, n) == 0`. +To check if a year is divisible by `n`, we can do `rem(year, n) == 0`. We can define a function to make the intent clearer. + +```elixir +defp divides?(n, d), do: rem(n, d) == 0 +``` Any approach to the problem will perform this check three times to check if a year is equally divisible by 4, 100 and 400. What will differ is what Elixir features we will use to combine the checks. @@ -29,7 +33,7 @@ A year is a leap year if We can use [boolean operators][boolean-operators] to combine the checks, for example, like so: ```elixir -rem(year, 400) == 0 or (rem(year, 100) != 0) and rem(year, 4) == 0 +divides?(year, 400) or (not(divides?(year, 100))) and divides?(year, 4) ``` In the [boolean operators appraoch][operators-approach] we discuss the details of the solution. It includes variations of the operators and their precendence. @@ -54,9 +58,9 @@ Similarly to the functions with guards, the order of the checks can be done insi ```elixir cond do - rem(year, 400) == 0 -> true - rem(year, 100) == 0 -> false - rem(year, 4) == 0 -> true + divides?(year, 400) -> true + divides?(year, 100) -> false + divides?(year, 4) -> true true -> false end ``` diff --git a/exercises/practice/leap/.approaches/operators/snippet.txt b/exercises/practice/leap/.approaches/operators/snippet.txt index 69c218682b..a02ed6683c 100644 --- a/exercises/practice/leap/.approaches/operators/snippet.txt +++ b/exercises/practice/leap/.approaches/operators/snippet.txt @@ -1,5 +1,5 @@ def leap_year?(year) do - rem(year, 400) == 0 - or (rem(year, 100) != 0) - and rem(year, 4) == 0 + divides?(year, 400) + or (not(divides?(year, 100))) + and divides?(year, 4) end \ No newline at end of file From 5038fcb788f0047fa2fcd0466fede49b0c1663d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Por=C4=99ba?= Date: Sun, 7 Jan 2024 15:07:41 +0000 Subject: [PATCH 07/33] more explicit parameters in divides? --- exercises/practice/leap/.approaches/introduction.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/practice/leap/.approaches/introduction.md b/exercises/practice/leap/.approaches/introduction.md index 7bb7e5a8c3..c7bdb1722a 100644 --- a/exercises/practice/leap/.approaches/introduction.md +++ b/exercises/practice/leap/.approaches/introduction.md @@ -16,7 +16,7 @@ all the numbers are non-negative, both could work, depending on the approach. To check if a year is divisible by `n`, we can do `rem(year, n) == 0`. We can define a function to make the intent clearer. ```elixir -defp divides?(n, d), do: rem(n, d) == 0 +defp divides?(number, divisor), do: rem(number, divisor) == 0 ``` Any approach to the problem will perform this check three times to check if a year is equally divisible by 4, 100 and 400. From 0e16a737b2cc748e286608fea390dd316f7a4c12 Mon Sep 17 00:00:00 2001 From: Angelika Tyborska Date: Mon, 8 Jan 2024 21:22:16 +0100 Subject: [PATCH 08/33] Include approach snippets in formatting --- bin/check_formatting.sh | 18 ++++++++++++++++++ bin/format_approach_snippets.sh | 14 ++++++++++++++ 2 files changed, 32 insertions(+) create mode 100755 bin/format_approach_snippets.sh diff --git a/bin/check_formatting.sh b/bin/check_formatting.sh index 3ab24923e3..c40a830265 100755 --- a/bin/check_formatting.sh +++ b/bin/check_formatting.sh @@ -1,5 +1,14 @@ #!/bin/bash +echo 'Temporarily transforming .txt snippets into .ex snippets' +FILES="exercises/**/**/.approaches/**/snippet.txt" +for file in $FILES +do + txt_file_path=$file + ex_file_path="${file//\.txt/.ex}" + mv $txt_file_path $ex_file_path +done + # ### # check_formatting.sh # ### @@ -10,6 +19,15 @@ echo "Running 'mix format'" mix format --check-formatted FORMAT_EXIT_CODE="$?" +echo 'Transforming snippets back to .txt' +FILES="exercises/**/**/.approaches/**/snippet.ex" +for file in $FILES +do + ex_file_path=$file + txt_file_path="${file//\.ex/.txt}" + mv $ex_file_path $txt_file_path +done + echo "Checking for trailing whitespace" # git grep returns a 0 status if there is a match # so we negate the result for consistency diff --git a/bin/format_approach_snippets.sh b/bin/format_approach_snippets.sh new file mode 100755 index 0000000000..2940bff3ff --- /dev/null +++ b/bin/format_approach_snippets.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +# this script is necessary as long as +# the config option approaches.snippet_extension is not supported +# and we're forced to keep snippets in txt files +FILES="exercises/**/**/.approaches/**/snippet.txt" +for file in $FILES +do + txt_file_path=$file + ex_file_path="${file//\.txt/.ex}" + mv $txt_file_path $ex_file_path + mix format $ex_file_path + mv $ex_file_path $txt_file_path +done From 0d19aa2968e641f6789d0f2456c8eea562ceca67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Por=C4=99ba?= Date: Wed, 10 Jan 2024 17:51:12 +0000 Subject: [PATCH 09/33] Update exercises/practice/leap/.approaches/introduction.md Co-authored-by: Angelika Tyborska --- exercises/practice/leap/.approaches/introduction.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/practice/leap/.approaches/introduction.md b/exercises/practice/leap/.approaches/introduction.md index c7bdb1722a..6a574305d2 100644 --- a/exercises/practice/leap/.approaches/introduction.md +++ b/exercises/practice/leap/.approaches/introduction.md @@ -11,7 +11,7 @@ Instead, it provides [`rem/2`][rem] guard and the [`Integer.mod/2`][mod] functio The two functions differ in how they work with negative numbers, but since, in this exercise, all the numbers are non-negative, both could work, depending on the approach. -## General Solution +## General solution To check if a year is divisible by `n`, we can do `rem(year, n) == 0`. We can define a function to make the intent clearer. From 54a79e1881c735c7e5edd0b9388ce77a8c5129ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Por=C4=99ba?= Date: Wed, 10 Jan 2024 17:54:10 +0000 Subject: [PATCH 10/33] Update exercises/practice/leap/.approaches/introduction.md Co-authored-by: Angelika Tyborska --- exercises/practice/leap/.approaches/introduction.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/practice/leap/.approaches/introduction.md b/exercises/practice/leap/.approaches/introduction.md index 6a574305d2..e2d7b90ff9 100644 --- a/exercises/practice/leap/.approaches/introduction.md +++ b/exercises/practice/leap/.approaches/introduction.md @@ -38,7 +38,7 @@ divides?(year, 400) or (not(divides?(year, 100))) and divides?(year, 4) In the [boolean operators appraoch][operators-approach] we discuss the details of the solution. It includes variations of the operators and their precendence. -## Approach: Function Guards +## Approach: Multiple clause function Instead of using boolean operators, we can define multiple `leap_year?/1` functions with different guards. We can use the order of the definitions to ensure correct check. From 3c81c2c82b1294a55e97b6d0b5673e10b4c2e1ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Por=C4=99ba?= Date: Wed, 10 Jan 2024 17:54:30 +0000 Subject: [PATCH 11/33] Update exercises/practice/leap/.approaches/introduction.md Co-authored-by: Angelika Tyborska --- exercises/practice/leap/.approaches/introduction.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/practice/leap/.approaches/introduction.md b/exercises/practice/leap/.approaches/introduction.md index e2d7b90ff9..4fe10a974f 100644 --- a/exercises/practice/leap/.approaches/introduction.md +++ b/exercises/practice/leap/.approaches/introduction.md @@ -54,7 +54,7 @@ In the [functions with guards approach][guards-approach] we discuss why in this ## Approach: Using cond -Similarly to the functions with guards, the order of the checks can be done inside a function with `cond` expression. +Similarly to the multiple clause function approach, we can also use a `cond` expression. ```elixir cond do From 09d55caf355ac7b96ce3ef456fa7628150fb5ceb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Por=C4=99ba?= Date: Wed, 10 Jan 2024 17:55:07 +0000 Subject: [PATCH 12/33] Update exercises/practice/leap/.approaches/introduction.md Co-authored-by: Angelika Tyborska --- exercises/practice/leap/.approaches/introduction.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/practice/leap/.approaches/introduction.md b/exercises/practice/leap/.approaches/introduction.md index 4fe10a974f..d9dd047264 100644 --- a/exercises/practice/leap/.approaches/introduction.md +++ b/exercises/practice/leap/.approaches/introduction.md @@ -40,7 +40,7 @@ It includes variations of the operators and their precendence. ## Approach: Multiple clause function -Instead of using boolean operators, we can define multiple `leap_year?/1` functions with different guards. +Instead of using boolean operators, we can define multiple `leap_year?/1` function clauses with different guards. We can use the order of the definitions to ensure correct check. ```elixir From 085dfa3b6ec76e2546430b67b7ef992309490a89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Por=C4=99ba?= Date: Wed, 10 Jan 2024 17:58:13 +0000 Subject: [PATCH 13/33] Update exercises/practice/leap/.approaches/introduction.md Co-authored-by: Angelika Tyborska --- exercises/practice/leap/.approaches/introduction.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/exercises/practice/leap/.approaches/introduction.md b/exercises/practice/leap/.approaches/introduction.md index d9dd047264..104716827d 100644 --- a/exercises/practice/leap/.approaches/introduction.md +++ b/exercises/practice/leap/.approaches/introduction.md @@ -84,10 +84,10 @@ In the [case approach][case-approach] we discuss the pattern matchin in a case e [modulo]: https://en.wikipedia.org/wiki/Modulo -[operators]: https://hexdocs.pm/elixir/1.16.0/operators.html -[rem]: https://hexdocs.pm/elixir/1.16.0/Kernel.html#rem/2 -[mod]: https://hexdocs.pm/elixir/1.16.0/Integer.html#mod/2 -[boolean-operators]: https://hexdocs.pm/elixir/1.11.4/operators.html#general-operators +[operators]: https://hexdocs.pm/elixir/operators.html +[rem]: https://hexdocs.pm/elixir/Kernel.html#rem/2 +[mod]: https://hexdocs.pm/elixir/Integer.html#mod/2 +[boolean-operators]: https://hexdocs.pm/elixir/operators.html#general-operators [operators-approach]: https://exercism.org/tracks/elixir/exercises/leap/approaches/operators [guards-approach]: https://exercism.org/tracks/elixir/exercises/leap/approaches/guards [cond-approach]: https://exercism.org/tracks/elixir/exercises/leap/approaches/cond From 6e85e4fec2b60ab2b542c08522b8422d49a4b307 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Por=C4=99ba?= Date: Wed, 10 Jan 2024 17:58:37 +0000 Subject: [PATCH 14/33] Update exercises/practice/leap/.approaches/introduction.md Co-authored-by: Angelika Tyborska --- exercises/practice/leap/.approaches/introduction.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/practice/leap/.approaches/introduction.md b/exercises/practice/leap/.approaches/introduction.md index 104716827d..efa6712a8e 100644 --- a/exercises/practice/leap/.approaches/introduction.md +++ b/exercises/practice/leap/.approaches/introduction.md @@ -6,7 +6,7 @@ To solve the Leap problem, we must determine if a year is evenly divisible by a Such operation in computing is called [modulo][modulo]. Unlike many languages, Elixir does not have [operators][operators] for either integer division or modulo. -Instead, it provides [`rem/2`][rem] guard and the [`Integer.mod/2`][mod] function. +Instead, it provides the [`Kernel.rem/2`][rem] function and the [`Integer.mod/2`][mod] function. The two functions differ in how they work with negative numbers, but since, in this exercise, all the numbers are non-negative, both could work, depending on the approach. From 5eb78410fdc273491959cb07c23d47cf17771537 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Por=C4=99ba?= Date: Mon, 8 Jan 2024 21:01:58 +0000 Subject: [PATCH 15/33] reformatting --- exercises/practice/leap/.approaches/case/snippet.txt | 12 ++++++------ exercises/practice/leap/.approaches/cond/snippet.txt | 12 ++++++------ exercises/practice/leap/.approaches/introduction.md | 7 ++++--- .../practice/leap/.approaches/operators/snippet.txt | 6 +++--- 4 files changed, 19 insertions(+), 18 deletions(-) diff --git a/exercises/practice/leap/.approaches/case/snippet.txt b/exercises/practice/leap/.approaches/case/snippet.txt index 3e44884af3..56a025256c 100644 --- a/exercises/practice/leap/.approaches/case/snippet.txt +++ b/exercises/practice/leap/.approaches/case/snippet.txt @@ -1,8 +1,8 @@ def leap_year?(year) do - case { rem(year, 400), rem(year, 100), rem(year, 4) } do - { 0, _, _ } -> true - { _, 0, _ } -> false - { _, _, 0 } -> true - { _, _, _ } -> false - end + case { rem(year, 400), rem(year, 100), rem(year, 4) } do + { 0, _, _ } -> true + { _, 0, _ } -> false + { _, _, 0 } -> true + { _, _, _ } -> false + end end \ No newline at end of file diff --git a/exercises/practice/leap/.approaches/cond/snippet.txt b/exercises/practice/leap/.approaches/cond/snippet.txt index 184be26376..191c792cb0 100644 --- a/exercises/practice/leap/.approaches/cond/snippet.txt +++ b/exercises/practice/leap/.approaches/cond/snippet.txt @@ -1,8 +1,8 @@ def leap_year?(year) do - cond do - divides?(year, 400) -> true - divides?(year, 100) -> false - divides?(year, 4) -> true - true -> false - end + cond do + divides?(year, 400) -> true + divides?(year, 100) -> false + divides?(year, 4) -> true + true -> false + end end \ No newline at end of file diff --git a/exercises/practice/leap/.approaches/introduction.md b/exercises/practice/leap/.approaches/introduction.md index efa6712a8e..9d948bc409 100644 --- a/exercises/practice/leap/.approaches/introduction.md +++ b/exercises/practice/leap/.approaches/introduction.md @@ -13,14 +13,15 @@ all the numbers are non-negative, both could work, depending on the approach. ## General solution -To check if a year is divisible by `n`, we can do `rem(year, n) == 0`. We can define a function to make the intent clearer. +To check if a year is divisible by `n`, we can do `rem(year, n) == 0`. +We can define a function to make the intent clearer. ```elixir defp divides?(number, divisor), do: rem(number, divisor) == 0 ``` -Any approach to the problem will perform this check three times to check if a year is equally divisible by 4, 100 and 400. -What will differ is what Elixir features we will use to combine the checks. +Any approach to the problem will perform this check three times to see if a year is equally divisible by 4, 100 and 400. +What will differ between approaches is what Elixir features we will use to combine the checks. ## Approach: Boolean Operators diff --git a/exercises/practice/leap/.approaches/operators/snippet.txt b/exercises/practice/leap/.approaches/operators/snippet.txt index a02ed6683c..ae790d06be 100644 --- a/exercises/practice/leap/.approaches/operators/snippet.txt +++ b/exercises/practice/leap/.approaches/operators/snippet.txt @@ -1,5 +1,5 @@ def leap_year?(year) do - divides?(year, 400) - or (not(divides?(year, 100))) - and divides?(year, 4) + divides?(year, 400) + or (not(divides?(year, 100))) + and divides?(year, 4) end \ No newline at end of file From 510c33c35321d389b5fa21db2d0bc7f6e9ca2ede Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Por=C4=99ba?= Date: Thu, 11 Jan 2024 10:00:08 +0000 Subject: [PATCH 16/33] boolean operators approach --- .../practice/leap/.approaches/config.json | 2 +- .../practice/leap/.approaches/introduction.md | 10 +- .../leap/.approaches/operators/content.md | 93 ++++++++++++++++++- .../leap/.approaches/operators/snippet.txt | 8 +- 4 files changed, 102 insertions(+), 11 deletions(-) diff --git a/exercises/practice/leap/.approaches/config.json b/exercises/practice/leap/.approaches/config.json index 570db6f148..3bdadd1fef 100644 --- a/exercises/practice/leap/.approaches/config.json +++ b/exercises/practice/leap/.approaches/config.json @@ -8,7 +8,7 @@ { "uuid": "be6d6c6e-8e19-4657-aad5-3382e7ec01db", "slug": "operators", - "title": "Boolean Operators", + "title": "Boolean operators", "blurb": "Use boolean operators to combine the checks.", "authors": [ "michalporeba" diff --git a/exercises/practice/leap/.approaches/introduction.md b/exercises/practice/leap/.approaches/introduction.md index 9d948bc409..30c30b583c 100644 --- a/exercises/practice/leap/.approaches/introduction.md +++ b/exercises/practice/leap/.approaches/introduction.md @@ -6,7 +6,7 @@ To solve the Leap problem, we must determine if a year is evenly divisible by a Such operation in computing is called [modulo][modulo]. Unlike many languages, Elixir does not have [operators][operators] for either integer division or modulo. -Instead, it provides the [`Kernel.rem/2`][rem] function and the [`Integer.mod/2`][mod] function. +Instead, it provides the [`Kernel.rem/2`][rem] and the [`Integer.mod/2`][mod] functions. The two functions differ in how they work with negative numbers, but since, in this exercise, all the numbers are non-negative, both could work, depending on the approach. @@ -23,7 +23,7 @@ defp divides?(number, divisor), do: rem(number, divisor) == 0 Any approach to the problem will perform this check three times to see if a year is equally divisible by 4, 100 and 400. What will differ between approaches is what Elixir features we will use to combine the checks. -## Approach: Boolean Operators +## Approach: Boolean operators The full rules are as follows: A year is a leap year if @@ -39,7 +39,7 @@ divides?(year, 400) or (not(divides?(year, 100))) and divides?(year, 4) In the [boolean operators appraoch][operators-approach] we discuss the details of the solution. It includes variations of the operators and their precendence. -## Approach: Multiple clause function +## Approach: multiple clause function Instead of using boolean operators, we can define multiple `leap_year?/1` function clauses with different guards. We can use the order of the definitions to ensure correct check. @@ -53,7 +53,7 @@ def leap_year?(_), do: false In the [functions with guards approach][guards-approach] we discuss why in this approach the `Integer.mod/2` function will not work. -## Approach: Using cond +## Approach: using cond Similarly to the multiple clause function approach, we can also use a `cond` expression. @@ -68,7 +68,7 @@ end We discuss this briefly in the [cond approach][cond-approach] -## Approach: Using case +## Approach: using case Using `case` is yet another way to check for a leap year. This time, all the reminders are calculated and put into a tuple, and pattern matching is used to decide the outcome. diff --git a/exercises/practice/leap/.approaches/operators/content.md b/exercises/practice/leap/.approaches/operators/content.md index 5a046b77a9..ed875aaffe 100644 --- a/exercises/practice/leap/.approaches/operators/content.md +++ b/exercises/practice/leap/.approaches/operators/content.md @@ -1 +1,92 @@ -# Boolean Operators \ No newline at end of file +# Boolean operators + +```elixir +defmodule Year do + @spec divides?(non_neg_integer, non_neg_integer) :: boolean + defp divides?(number, divisor), do: rem(number, divisor) == 0 + + @spec leap_year?(non_neg_integer) :: boolean + def leap_year?(year) do + divides?(year, 4) and not divides?(year, 100) or divides?(year, 400) + end +end +``` + +## Short-circuiting + +At the core of this approach, three checks are returning three boolean values. +We can use [Boolean logic](https://en.wikipedia.org/wiki/Boolean_algebra) to combine the results. + +When using this approach, it is essential to consider short-circuiting of boolean operators. +The expression `left and right` can be only true if both `left` and `right` are *true*. +If `left` is *false*, `right` will not be evaluated. The result will be *false*. +However, if `left` is *true*, `right` has to be evaluated to determin the outcome. + +The expression `left or right` can be true if either `left` or `right` is *true*. +If `left` is *true*, `right` will not be evaluated. The result will be *true*. +However, if `left` is *false*, `right` has to be evaluated to determine the outcome. + + +## Precedence of operators + +Another thing to consider when using Boolean operators is their precedence. +```elixir +true or false and false +``` +The above evaluates to *true* because in Elixir `and` has higher precedence than `or`. +The above expression is equivalent to: +```elixir +true or (false and false) +``` +If `or` should be evaluated first, we must use parenthesis. +```elixir +(true or false) and false +``` +which equals to *false*. + +The `not` operator is evaluated before `and` and `or`. + +## Strict or relaxed? + +Elixir offers two sets of Boolean operators: strict and relaxed. +The strict versions `not`, `and`, `or` require the first (left) argument to be of [boolean type][hexdocs-booleans]. +The relaxed versions `!`, `&&`, `||` require the first argument to be only [truthy or falsy][hexdocs-truthy]. + +In the case of this exercise, both types will work equally well. + +## Being explicit + +The `leap_year?` function could be written like so: +```elixir +def leap_year?(year) do + rem(year, 4) == 0 and not rem(year, 100) == 0 or rem(year, 400) == 0 +end +``` +Some prefer this form, as it is very direct. We can see what is happening. +We are explicitly checking the reminder, comparing it to zero. + +```elixir +def leap_year?(year) do + divides?(year, 4) and not divides?(year, 100) or divides?(year, 400) +end +``` +Other might prefer the above form, which requires defining the `devides?` function. +By doing so, we can be explicit about the *intent*. +We want to check if a year can be equally divided into a number. + +Yet another approach might be use variables to capture the results of individual checks. + +```elixir +def leap_year?(year) do + by4? = divides?(year, 4) + by100? = divides?(year, 100) + by400? = divides?(year, 400) + by4? and not by100? or by400? +end +``` + +All versions of the code will work. Which one to choose is often a personal or sometimes a team preference. What reads best for you? What will make most sense to you when you look at the code again? + +[hexdocs-booleans]: https://hexdocs.pm/elixir/basic-types.html#booleans-and-nil +[hexdocs-truthy]: https://hexdocs.pm/elixir/Kernel.html#module-truthy-and-falsy-values +[exercism-booleans]: https://exercism.org/tracks/elixir/concepts/booleans \ No newline at end of file diff --git a/exercises/practice/leap/.approaches/operators/snippet.txt b/exercises/practice/leap/.approaches/operators/snippet.txt index ae790d06be..efa2ae8fde 100644 --- a/exercises/practice/leap/.approaches/operators/snippet.txt +++ b/exercises/practice/leap/.approaches/operators/snippet.txt @@ -1,5 +1,5 @@ def leap_year?(year) do - divides?(year, 400) - or (not(divides?(year, 100))) - and divides?(year, 4) -end \ No newline at end of file + divides?(year, 4) and + not divides?(year, 100) or + divides?(year, 400) +end From fc4a44c1e2a2213c6497bcc63a388037a23e5b28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Por=C4=99ba?= Date: Thu, 11 Jan 2024 10:25:12 +0000 Subject: [PATCH 17/33] rem by default, divides? as an option --- .../practice/leap/.approaches/introduction.md | 14 +++++------- .../leap/.approaches/operators/content.md | 22 ++++++++++++------- .../leap/.approaches/operators/snippet.txt | 6 ++--- 3 files changed, 22 insertions(+), 20 deletions(-) diff --git a/exercises/practice/leap/.approaches/introduction.md b/exercises/practice/leap/.approaches/introduction.md index 30c30b583c..9ccb43dee0 100644 --- a/exercises/practice/leap/.approaches/introduction.md +++ b/exercises/practice/leap/.approaches/introduction.md @@ -14,11 +14,6 @@ all the numbers are non-negative, both could work, depending on the approach. ## General solution To check if a year is divisible by `n`, we can do `rem(year, n) == 0`. -We can define a function to make the intent clearer. - -```elixir -defp divides?(number, divisor), do: rem(number, divisor) == 0 -``` Any approach to the problem will perform this check three times to see if a year is equally divisible by 4, 100 and 400. What will differ between approaches is what Elixir features we will use to combine the checks. @@ -34,7 +29,7 @@ A year is a leap year if We can use [boolean operators][boolean-operators] to combine the checks, for example, like so: ```elixir -divides?(year, 400) or (not(divides?(year, 100))) and divides?(year, 4) +rem(year, 5) == 0 and not rem(year, 100) == 0 or rem(year, 400) == 0 ``` In the [boolean operators appraoch][operators-approach] we discuss the details of the solution. It includes variations of the operators and their precendence. @@ -59,9 +54,9 @@ Similarly to the multiple clause function approach, we can also use a `cond` exp ```elixir cond do - divides?(year, 400) -> true - divides?(year, 100) -> false - divides?(year, 4) -> true + rem(year, 400) == 0 -> true + rem(year, 100) == 0 -> false + rem(year, 4) == 0 -> true true -> false end ``` @@ -81,6 +76,7 @@ case { rem(year, 400), rem(year, 100), rem(year, 4) } do { _, _, _ } -> false end ``` + In the [case approach][case-approach] we discuss the pattern matchin in a case expression. diff --git a/exercises/practice/leap/.approaches/operators/content.md b/exercises/practice/leap/.approaches/operators/content.md index ed875aaffe..cef6495433 100644 --- a/exercises/practice/leap/.approaches/operators/content.md +++ b/exercises/practice/leap/.approaches/operators/content.md @@ -2,12 +2,9 @@ ```elixir defmodule Year do - @spec divides?(non_neg_integer, non_neg_integer) :: boolean - defp divides?(number, divisor), do: rem(number, divisor) == 0 - @spec leap_year?(non_neg_integer) :: boolean def leap_year?(year) do - divides?(year, 4) and not divides?(year, 100) or divides?(year, 400) + rem(year, 4) == 0 and not rem(year, 100) == 0 or rem(year, 400) == 0 end end ``` @@ -26,7 +23,6 @@ The expression `left or right` can be true if either `left` or `right` is *true* If `left` is *true*, `right` will not be evaluated. The result will be *true*. However, if `left` is *false*, `right` has to be evaluated to determine the outcome. - ## Precedence of operators Another thing to consider when using Boolean operators is their precedence. @@ -52,7 +48,12 @@ Elixir offers two sets of Boolean operators: strict and relaxed. The strict versions `not`, `and`, `or` require the first (left) argument to be of [boolean type][hexdocs-booleans]. The relaxed versions `!`, `&&`, `||` require the first argument to be only [truthy or falsy][hexdocs-truthy]. -In the case of this exercise, both types will work equally well. +In the case of this exercise, both types will work equally well, so the solution could be: +```elixir +def leap_year?(year) do + rem(year, 4) == 0 && !(rem(year, 100) == 0) || rem(year, 400) == 0 +end +``` ## Being explicit @@ -62,19 +63,24 @@ def leap_year?(year) do rem(year, 4) == 0 and not rem(year, 100) == 0 or rem(year, 400) == 0 end ``` + Some prefer this form, as it is very direct. We can see what is happening. We are explicitly checking the reminder, comparing it to zero. ```elixir +defp divides?(number, divisor), do: rem(number, divisor) == 0 + def leap_year?(year) do divides?(year, 4) and not divides?(year, 100) or divides?(year, 400) end ``` -Other might prefer the above form, which requires defining the `devides?` function. + +Other might prefer the above form, which requires defining the `devides?` function or something similar. By doing so, we can be explicit about the *intent*. We want to check if a year can be equally divided into a number. -Yet another approach might be use variables to capture the results of individual checks. +Yet another approach might be to use variables to capture the results of individual checks and provided the extra meaning. +This approach also shortens the check so the Boolean operators and relationships between them are more prominent. ```elixir def leap_year?(year) do diff --git a/exercises/practice/leap/.approaches/operators/snippet.txt b/exercises/practice/leap/.approaches/operators/snippet.txt index efa2ae8fde..50ba418ce3 100644 --- a/exercises/practice/leap/.approaches/operators/snippet.txt +++ b/exercises/practice/leap/.approaches/operators/snippet.txt @@ -1,5 +1,5 @@ def leap_year?(year) do - divides?(year, 4) and - not divides?(year, 100) or - divides?(year, 400) + rem(year, 4) == 0 and + not rem(year, 100) == 0 or + rem(year, 400) == 0 end From f98d44f1e0c1ece9c3472eef41d0af8a23f87ab2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Por=C4=99ba?= Date: Thu, 11 Jan 2024 20:43:39 +0000 Subject: [PATCH 18/33] Update exercises/practice/leap/.approaches/introduction.md Co-authored-by: Angelika Tyborska --- exercises/practice/leap/.approaches/introduction.md | 1 - 1 file changed, 1 deletion(-) diff --git a/exercises/practice/leap/.approaches/introduction.md b/exercises/practice/leap/.approaches/introduction.md index 9ccb43dee0..820ecdab3a 100644 --- a/exercises/practice/leap/.approaches/introduction.md +++ b/exercises/practice/leap/.approaches/introduction.md @@ -37,7 +37,6 @@ It includes variations of the operators and their precendence. ## Approach: multiple clause function Instead of using boolean operators, we can define multiple `leap_year?/1` function clauses with different guards. -We can use the order of the definitions to ensure correct check. ```elixir def leap_year?(year) when rem(year, 400) == 0, do: true From b9bd5595dc548fb02e2864c69129e5ea1d7ead65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Por=C4=99ba?= Date: Fri, 12 Jan 2024 21:25:08 +0000 Subject: [PATCH 19/33] functions approach --- .../practice/leap/.approaches/config.json | 6 +-- .../leap/.approaches/functions/content.md | 50 +++++++++++++++++++ .../{guards => functions}/snippet.txt | 2 +- .../leap/.approaches/guards/content.md | 1 - .../practice/leap/.approaches/introduction.md | 4 +- 5 files changed, 56 insertions(+), 7 deletions(-) create mode 100644 exercises/practice/leap/.approaches/functions/content.md rename exercises/practice/leap/.approaches/{guards => functions}/snippet.txt (85%) delete mode 100644 exercises/practice/leap/.approaches/guards/content.md diff --git a/exercises/practice/leap/.approaches/config.json b/exercises/practice/leap/.approaches/config.json index 3bdadd1fef..9e110daf64 100644 --- a/exercises/practice/leap/.approaches/config.json +++ b/exercises/practice/leap/.approaches/config.json @@ -16,9 +16,9 @@ }, { "uuid": "0267853e-9607-4b60-b2f9-e4a34f5316db", - "slug": "guards", - "title": "Function Guards", - "blurb": "Use function guards to control order of checks.", + "slug": "functions", + "title": "Multiple clause functions", + "blurb": "Use multiple clause function to control the order of checks.", "authors": [ "michalporeba" ] diff --git a/exercises/practice/leap/.approaches/functions/content.md b/exercises/practice/leap/.approaches/functions/content.md new file mode 100644 index 0000000000..a8183f547d --- /dev/null +++ b/exercises/practice/leap/.approaches/functions/content.md @@ -0,0 +1,50 @@ +# Multiple clause functions + +```elixir +defmodule Year do + @spec leap_year?(non_neg_integer) :: boolean + def leap_year?(year) when rem(year, 400) == 0, do: true + def leap_year?(year) when rem(year, 100) == 0, do: false + def leap_year?(year) when rem(year, 4) == 0, do: true + def leap_year?(_), do: false +end +``` + +In Elixir, functions can have multiple clauses. +Which one will be executed depends on parameter matching and guards. +When a function with multiple clauses is invoked, the parameters are compared to the definitions in the order in which they were defined, and only the first one matching will be invoked. + +While in the [operators approach][operators-approach], it was possible to reorder expressions as long as the suitable boolean operators were used, in this approach, there is only one correct order of definitions. + +In our case, the three guards in the function clauses are as follows: + +```elixir +when rem(year, 400) == 0 +when rem(year, 100) == 0 +when rem(year, 4) == 0 +``` + +But because of the order they are evaluated in, they are equivalent to: + +```elixir +when rem(year, 400) == 0 +when rem(year, 100) == 0 and not rem(year, 400) == 0 +when rem(year, 4) == 0 and not rem(year, 100) == 0 and not rem(year, 400) = 0 +``` + +The final clause, `def leap_year?(_), do: false`, returns false if previous clauses are not a match. + +## Guards + +The [guards][guards] are part of the pattern-matching mechanism. +They allow for more complex checks of values. +However, because of when they are executed to allow the compiler to perform necessary optimization, +only a minimal subset of operations are permitted. +`Kernel.rem/2` is on this limited list, and `Integer.mod/2` is not. +This is why, in this approach, only the first one will work, and the latter will not. + +In this approach, the boolean operators matter too. Only the strict ones, `not`, `and`, `or` are allowed. +The relaxed `!`, `&&`, `||` will fail to compile. + +[operators-approach]: https://exercism.org/tracks/elixir/exercises/leap/approaches/operators +[guards]: https://hexdocs.pm/elixir/main/patterns-and-guards.html#guards \ No newline at end of file diff --git a/exercises/practice/leap/.approaches/guards/snippet.txt b/exercises/practice/leap/.approaches/functions/snippet.txt similarity index 85% rename from exercises/practice/leap/.approaches/guards/snippet.txt rename to exercises/practice/leap/.approaches/functions/snippet.txt index 5880d5c450..c0d338e3c3 100644 --- a/exercises/practice/leap/.approaches/guards/snippet.txt +++ b/exercises/practice/leap/.approaches/functions/snippet.txt @@ -1,4 +1,4 @@ def leap_year?(year) when rem(year, 400) == 0, do: true def leap_year?(year) when rem(year, 100) == 0, do: false def leap_year?(year) when rem(year, 4) == 0, do: true -def leap_year?(_), do: false \ No newline at end of file +def leap_year?(_), do: false diff --git a/exercises/practice/leap/.approaches/guards/content.md b/exercises/practice/leap/.approaches/guards/content.md deleted file mode 100644 index cb94d6f0c6..0000000000 --- a/exercises/practice/leap/.approaches/guards/content.md +++ /dev/null @@ -1 +0,0 @@ -# Function Guards \ No newline at end of file diff --git a/exercises/practice/leap/.approaches/introduction.md b/exercises/practice/leap/.approaches/introduction.md index 820ecdab3a..fb9a56b42c 100644 --- a/exercises/practice/leap/.approaches/introduction.md +++ b/exercises/practice/leap/.approaches/introduction.md @@ -45,7 +45,7 @@ def leap_year?(year) when rem(year, 4) == 0, do: true def leap_year?(_), do: false ``` -In the [functions with guards approach][guards-approach] we discuss why in this approach the `Integer.mod/2` function will not work. +In the [multiple clause functions approach][functions-approach] we discuss why in this approach the `Integer.mod/2` function will not work. ## Approach: using cond @@ -85,7 +85,7 @@ In the [case approach][case-approach] we discuss the pattern matchin in a case e [mod]: https://hexdocs.pm/elixir/Integer.html#mod/2 [boolean-operators]: https://hexdocs.pm/elixir/operators.html#general-operators [operators-approach]: https://exercism.org/tracks/elixir/exercises/leap/approaches/operators -[guards-approach]: https://exercism.org/tracks/elixir/exercises/leap/approaches/guards +[functions-approach]: https://exercism.org/tracks/elixir/exercises/leap/approaches/functions [cond-approach]: https://exercism.org/tracks/elixir/exercises/leap/approaches/cond [case-approach]: https://exercism.org/tracks/elixir/exercises/leap/approaches/case From 431da1db74863ee8d80bc917133e83486cbea8c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Por=C4=99ba?= Date: Sat, 13 Jan 2024 00:10:40 +0000 Subject: [PATCH 20/33] control flow approaches --- .../practice/leap/.approaches/case/content.md | 1 - .../leap/.approaches/case/snippet.txt | 8 -- .../practice/leap/.approaches/cond/content.md | 1 - .../leap/.approaches/cond/snippet.txt | 8 -- .../practice/leap/.approaches/config.json | 15 +-- .../practice/leap/.approaches/flow/content.md | 97 +++++++++++++++++++ .../leap/.approaches/flow/snippet.txt | 7 ++ .../leap/.approaches/functions/content.md | 4 +- .../practice/leap/.approaches/introduction.md | 27 ++---- 9 files changed, 118 insertions(+), 50 deletions(-) delete mode 100644 exercises/practice/leap/.approaches/case/content.md delete mode 100644 exercises/practice/leap/.approaches/case/snippet.txt delete mode 100644 exercises/practice/leap/.approaches/cond/content.md delete mode 100644 exercises/practice/leap/.approaches/cond/snippet.txt create mode 100644 exercises/practice/leap/.approaches/flow/content.md create mode 100644 exercises/practice/leap/.approaches/flow/snippet.txt diff --git a/exercises/practice/leap/.approaches/case/content.md b/exercises/practice/leap/.approaches/case/content.md deleted file mode 100644 index cba6194a61..0000000000 --- a/exercises/practice/leap/.approaches/case/content.md +++ /dev/null @@ -1 +0,0 @@ -# Using `case` \ No newline at end of file diff --git a/exercises/practice/leap/.approaches/case/snippet.txt b/exercises/practice/leap/.approaches/case/snippet.txt deleted file mode 100644 index 56a025256c..0000000000 --- a/exercises/practice/leap/.approaches/case/snippet.txt +++ /dev/null @@ -1,8 +0,0 @@ -def leap_year?(year) do - case { rem(year, 400), rem(year, 100), rem(year, 4) } do - { 0, _, _ } -> true - { _, 0, _ } -> false - { _, _, 0 } -> true - { _, _, _ } -> false - end -end \ No newline at end of file diff --git a/exercises/practice/leap/.approaches/cond/content.md b/exercises/practice/leap/.approaches/cond/content.md deleted file mode 100644 index 0c86112b86..0000000000 --- a/exercises/practice/leap/.approaches/cond/content.md +++ /dev/null @@ -1 +0,0 @@ -# Using `cond` \ No newline at end of file diff --git a/exercises/practice/leap/.approaches/cond/snippet.txt b/exercises/practice/leap/.approaches/cond/snippet.txt deleted file mode 100644 index 191c792cb0..0000000000 --- a/exercises/practice/leap/.approaches/cond/snippet.txt +++ /dev/null @@ -1,8 +0,0 @@ -def leap_year?(year) do - cond do - divides?(year, 400) -> true - divides?(year, 100) -> false - divides?(year, 4) -> true - true -> false - end -end \ No newline at end of file diff --git a/exercises/practice/leap/.approaches/config.json b/exercises/practice/leap/.approaches/config.json index 9e110daf64..a8199ca989 100644 --- a/exercises/practice/leap/.approaches/config.json +++ b/exercises/practice/leap/.approaches/config.json @@ -25,18 +25,9 @@ }, { "uuid": "428e3cee-309a-4c45-a6d4-3bff4eb41daa", - "slug": "cond", - "title": "Cond", - "blurb": "Use `cond` to control order of checks.", - "authors": [ - "michalporeba" - ] - }, - { - "uuid": "129e6863-275b-4fa3-abfe-4cb07c97acae", - "slug": "case", - "title": "Case", - "blurb": "Use `case` and tuples to decide if the year is a leap one.", + "slug": "flow", + "title": "Control flow structures", + "blurb": "Use `if, `case` or `cond`, to control order of checks.", "authors": [ "michalporeba" ] diff --git a/exercises/practice/leap/.approaches/flow/content.md b/exercises/practice/leap/.approaches/flow/content.md new file mode 100644 index 0000000000..aca9f23389 --- /dev/null +++ b/exercises/practice/leap/.approaches/flow/content.md @@ -0,0 +1,97 @@ +# Condition flow structures + +```elixir +defmodule Year do + @spec leap_year?(non_neg_integer) :: boolean + def leap_year?(year) do + if rem(year, 100) == 0 do + rem(year, 400) == 0 + else + rem(year, 4) == 0 + end + end +end +``` + +## If + +Elixir provides for [condition flow structures][hexdocs-structures]: `case`, `cond`, `if`, and `unless`. +The `if` and `unless` allow to evaluate only one condition. +Unlike in many other languages, there is no `else if` option in Elixir. + +However, in this case, it is not necessary. We can use `if` once to check if the year is divisible by 100. +If it is, then whether it is a leap year or not depends if it is divisible by 400. +If it is not, then whether it is a leap year or not depends if it is divisible by 4. + +```elixir +def leap_year?(year) do + if rem(year, 100) == 0 do + rem(year, 400) == 0 + else + rem(year, 4) == 0 + end +end +``` + +## Cond + +Another option is `cond` which allows for evaluating multiple conditions, similar to `else if` in other languages. + +```elixir +def leap_year?(year) do + cond do + rem(year, 400) == 0 -> true + rem(year, 100) == 0 -> false + rem(year, 4) == 0 -> true + true -> false + end +end +``` + +Similarly to the [functions approach][functions-approach], the order here matters. +The conditions are evaluated in order, and the first that is not `nil` or `false` leads to the result. + +## Case + +`case` allows to compare a value to multiple patterns, but can also replicate what `if` offers. + +```elixir +def leap_year?(year) do + case rem(year, 100) do + 0 -> rem(year, 400) == 0 + _ -> rem(year, 4) == 0 + end +end +``` + +But `case` also supports [guards][hexdocs-guards], offering another way to solve the problem. + +```elixir +def leap_year?(year) do + case year do + _ when rem(year, 400) == 0 -> true + _ when rem(year, 100) == 0 -> false + _ when rem(year, 4) == 0 -> true + _ -> false + end +end +``` + +`case` can be very flexible, supporting pattern matching on a tuple. +In this case, a tuple is created with all three checks. +Then, pattern matching to tuples is performed. + +```elixir +def leap_year?(year) do + case { rem(year, 400), rem(year, 100), rem(year, 4) } do + { 0, _, _ } -> true + { _, 0, _ } -> false + { _, _, 0 } -> true + _ -> false + end +end +``` + +[hexdocs-structures]: https://hexdocs.pm/elixir/case-cond-and-if.html +[hexdocs-guards]: https://hexdocs.pm/elixir/main/patterns-and-guards.html#guards +[functions-approach]: https://exercism.org/tracks/elixir/exercises/leap/approaches/functions \ No newline at end of file diff --git a/exercises/practice/leap/.approaches/flow/snippet.txt b/exercises/practice/leap/.approaches/flow/snippet.txt new file mode 100644 index 0000000000..22e1a70505 --- /dev/null +++ b/exercises/practice/leap/.approaches/flow/snippet.txt @@ -0,0 +1,7 @@ +def leap_year?(year) do + if rem(year, 100) == 0 do + rem(year, 400) == 0 + else + rem(year, 4) == 0 + end +end diff --git a/exercises/practice/leap/.approaches/functions/content.md b/exercises/practice/leap/.approaches/functions/content.md index a8183f547d..452a6bd877 100644 --- a/exercises/practice/leap/.approaches/functions/content.md +++ b/exercises/practice/leap/.approaches/functions/content.md @@ -36,7 +36,7 @@ The final clause, `def leap_year?(_), do: false`, returns false if previous clau ## Guards -The [guards][guards] are part of the pattern-matching mechanism. +The [guards][hexdocs-guards] are part of the pattern-matching mechanism. They allow for more complex checks of values. However, because of when they are executed to allow the compiler to perform necessary optimization, only a minimal subset of operations are permitted. @@ -47,4 +47,4 @@ In this approach, the boolean operators matter too. Only the strict ones, `not`, The relaxed `!`, `&&`, `||` will fail to compile. [operators-approach]: https://exercism.org/tracks/elixir/exercises/leap/approaches/operators -[guards]: https://hexdocs.pm/elixir/main/patterns-and-guards.html#guards \ No newline at end of file +[hexdocs-guards]: https://hexdocs.pm/elixir/main/patterns-and-guards.html#guards \ No newline at end of file diff --git a/exercises/practice/leap/.approaches/introduction.md b/exercises/practice/leap/.approaches/introduction.md index fb9a56b42c..f4a0ea1ab5 100644 --- a/exercises/practice/leap/.approaches/introduction.md +++ b/exercises/practice/leap/.approaches/introduction.md @@ -47,26 +47,19 @@ def leap_year?(_), do: false In the [multiple clause functions approach][functions-approach] we discuss why in this approach the `Integer.mod/2` function will not work. -## Approach: using cond +## Approach: control flow structures -Similarly to the multiple clause function approach, we can also use a `cond` expression. +In addition to the above two approaches, control flow structures offer a number of solutions. +Here are two examples using `if` and `case`. ```elixir -cond do - rem(year, 400) == 0 -> true - rem(year, 100) == 0 -> false - rem(year, 4) == 0 -> true - true -> false +if rem(year, 100) == 0 do + rem(year, 400) == 0 +else + rem(year, 4) == 0 end ``` -We discuss this briefly in the [cond approach][cond-approach] - -## Approach: using case - -Using `case` is yet another way to check for a leap year. -This time, all the reminders are calculated and put into a tuple, and pattern matching is used to decide the outcome. - ```elixir case { rem(year, 400), rem(year, 100), rem(year, 4) } do { 0, _, _ } -> true @@ -76,8 +69,7 @@ case { rem(year, 400), rem(year, 100), rem(year, 4) } do end ``` -In the [case approach][case-approach] we discuss the pattern matchin in a case expression. - +We discuss these and other solutions depending on various control flow structures in the [control flow structures approach][flow-approach]. [modulo]: https://en.wikipedia.org/wiki/Modulo [operators]: https://hexdocs.pm/elixir/operators.html @@ -86,7 +78,6 @@ In the [case approach][case-approach] we discuss the pattern matchin in a case e [boolean-operators]: https://hexdocs.pm/elixir/operators.html#general-operators [operators-approach]: https://exercism.org/tracks/elixir/exercises/leap/approaches/operators [functions-approach]: https://exercism.org/tracks/elixir/exercises/leap/approaches/functions -[cond-approach]: https://exercism.org/tracks/elixir/exercises/leap/approaches/cond -[case-approach]: https://exercism.org/tracks/elixir/exercises/leap/approaches/case +[flow-approach]: https://exercism.org/tracks/elixir/exercises/leap/approaches/cond From deb494f49f1b7d95c459a659593b6525e7cb060e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Por=C4=99ba?= Date: Sat, 13 Jan 2024 10:33:21 +0000 Subject: [PATCH 21/33] Update exercises/practice/leap/.approaches/introduction.md Co-authored-by: Angelika Tyborska --- exercises/practice/leap/.approaches/introduction.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/exercises/practice/leap/.approaches/introduction.md b/exercises/practice/leap/.approaches/introduction.md index f4a0ea1ab5..c8ed28ff6a 100644 --- a/exercises/practice/leap/.approaches/introduction.md +++ b/exercises/practice/leap/.approaches/introduction.md @@ -31,8 +31,8 @@ We can use [boolean operators][boolean-operators] to combine the checks, for exa ```elixir rem(year, 5) == 0 and not rem(year, 100) == 0 or rem(year, 400) == 0 ``` -In the [boolean operators appraoch][operators-approach] we discuss the details of the solution. -It includes variations of the operators and their precendence. +In the [boolean operators approach][operators-approach] we discuss the details of the solution. +It includes variations of the operators and their precedence. ## Approach: multiple clause function From ff5bc096ccdf1d8796c47ae1dec5be2be2a5b09a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Por=C4=99ba?= Date: Sat, 13 Jan 2024 10:33:51 +0000 Subject: [PATCH 22/33] Update exercises/practice/leap/.approaches/flow/content.md Co-authored-by: Angelika Tyborska --- exercises/practice/leap/.approaches/flow/content.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/practice/leap/.approaches/flow/content.md b/exercises/practice/leap/.approaches/flow/content.md index aca9f23389..a4903e63e8 100644 --- a/exercises/practice/leap/.approaches/flow/content.md +++ b/exercises/practice/leap/.approaches/flow/content.md @@ -15,7 +15,7 @@ end ## If -Elixir provides for [condition flow structures][hexdocs-structures]: `case`, `cond`, `if`, and `unless`. +Elixir provides for [control flow structures][hexdocs-structures]: `case`, `cond`, `if`, and `unless`. The `if` and `unless` allow to evaluate only one condition. Unlike in many other languages, there is no `else if` option in Elixir. From 8db3e1ebbbd11d8636f78816b40315d336d035c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Por=C4=99ba?= Date: Sat, 13 Jan 2024 10:34:07 +0000 Subject: [PATCH 23/33] Update exercises/practice/leap/.approaches/flow/content.md Co-authored-by: Angelika Tyborska --- exercises/practice/leap/.approaches/flow/content.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/practice/leap/.approaches/flow/content.md b/exercises/practice/leap/.approaches/flow/content.md index a4903e63e8..47af9cf9d5 100644 --- a/exercises/practice/leap/.approaches/flow/content.md +++ b/exercises/practice/leap/.approaches/flow/content.md @@ -1,4 +1,4 @@ -# Condition flow structures +# Control flow structures ```elixir defmodule Year do From 0754b52b5490b7b86bbbac4649538afa104bbe83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Por=C4=99ba?= Date: Sat, 13 Jan 2024 10:34:28 +0000 Subject: [PATCH 24/33] Update exercises/practice/leap/.approaches/functions/content.md Co-authored-by: Angelika Tyborska --- exercises/practice/leap/.approaches/functions/content.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/practice/leap/.approaches/functions/content.md b/exercises/practice/leap/.approaches/functions/content.md index 452a6bd877..41c0f623d9 100644 --- a/exercises/practice/leap/.approaches/functions/content.md +++ b/exercises/practice/leap/.approaches/functions/content.md @@ -1,4 +1,4 @@ -# Multiple clause functions +# Multiple clause function ```elixir defmodule Year do From 33e7fc62c09dd98029aa1c27f527c0c0d8f9302d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Por=C4=99ba?= Date: Sat, 13 Jan 2024 10:34:43 +0000 Subject: [PATCH 25/33] Update exercises/practice/leap/.approaches/introduction.md Co-authored-by: Angelika Tyborska --- exercises/practice/leap/.approaches/introduction.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/practice/leap/.approaches/introduction.md b/exercises/practice/leap/.approaches/introduction.md index c8ed28ff6a..69bf62c37e 100644 --- a/exercises/practice/leap/.approaches/introduction.md +++ b/exercises/practice/leap/.approaches/introduction.md @@ -65,7 +65,7 @@ case { rem(year, 400), rem(year, 100), rem(year, 4) } do { 0, _, _ } -> true { _, 0, _ } -> false { _, _, 0 } -> true - { _, _, _ } -> false + true -> false end ``` From a930e7f4a5adc7fd33549017bebe19af352d253a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Por=C4=99ba?= Date: Sat, 13 Jan 2024 10:35:05 +0000 Subject: [PATCH 26/33] Update exercises/practice/leap/.approaches/introduction.md Co-authored-by: Angelika Tyborska --- exercises/practice/leap/.approaches/introduction.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/practice/leap/.approaches/introduction.md b/exercises/practice/leap/.approaches/introduction.md index 69bf62c37e..aeb287926c 100644 --- a/exercises/practice/leap/.approaches/introduction.md +++ b/exercises/practice/leap/.approaches/introduction.md @@ -45,7 +45,7 @@ def leap_year?(year) when rem(year, 4) == 0, do: true def leap_year?(_), do: false ``` -In the [multiple clause functions approach][functions-approach] we discuss why in this approach the `Integer.mod/2` function will not work. +In the [multiple clause function approach][functions-approach] we discuss why in this approach the `Integer.mod/2` function will not work. ## Approach: control flow structures From 06d05d2dfda17f06c252dfc13a506318e4ec46f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Por=C4=99ba?= Date: Sat, 13 Jan 2024 11:48:14 +0000 Subject: [PATCH 27/33] Case on the tuple is the most idiomatic I have adjusted the text to make it clear that while there are many ways to use a case statement, the case on the tuple is the most idiomatic one. --- exercises/practice/leap/.approaches/flow/content.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/exercises/practice/leap/.approaches/flow/content.md b/exercises/practice/leap/.approaches/flow/content.md index 47af9cf9d5..ef251a9f24 100644 --- a/exercises/practice/leap/.approaches/flow/content.md +++ b/exercises/practice/leap/.approaches/flow/content.md @@ -64,7 +64,7 @@ def leap_year?(year) do end ``` -But `case` also supports [guards][hexdocs-guards], offering another way to solve the problem. +It also supports [guards][hexdocs-guards], offering another way to solve the problem. ```elixir def leap_year?(year) do @@ -77,8 +77,9 @@ def leap_year?(year) do end ``` -`case` can be very flexible, supporting pattern matching on a tuple. -In this case, a tuple is created with all three checks. +The `case` can be very flexible, so many variations are possible. +Using it with pattern matching on a tuple is considered **the most idiomatic**. +In this case, a tuple is created with all the checks. Then, pattern matching to tuples is performed. ```elixir From 19a3bb6b7ea24ed52ccd6973085c8e256a468fdc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Por=C4=99ba?= Date: Sat, 13 Jan 2024 12:02:39 +0000 Subject: [PATCH 28/33] typo --- exercises/practice/leap/.approaches/flow/content.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/practice/leap/.approaches/flow/content.md b/exercises/practice/leap/.approaches/flow/content.md index ef251a9f24..6cc82f0412 100644 --- a/exercises/practice/leap/.approaches/flow/content.md +++ b/exercises/practice/leap/.approaches/flow/content.md @@ -15,7 +15,7 @@ end ## If -Elixir provides for [control flow structures][hexdocs-structures]: `case`, `cond`, `if`, and `unless`. +Elixir provides four [control flow structures][hexdocs-structures]: `case`, `cond`, `if`, and `unless`. The `if` and `unless` allow to evaluate only one condition. Unlike in many other languages, there is no `else if` option in Elixir. From 6e527c758826caee9e63af1bc9c74515fc514c53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Por=C4=99ba?= Date: Sat, 13 Jan 2024 12:27:07 +0000 Subject: [PATCH 29/33] clauses not functions --- .../leap/.approaches/{functions => clauses}/content.md | 0 .../leap/.approaches/{functions => clauses}/snippet.txt | 0 exercises/practice/leap/.approaches/config.json | 4 ++-- exercises/practice/leap/.approaches/flow/content.md | 4 ++-- exercises/practice/leap/.approaches/introduction.md | 4 ++-- 5 files changed, 6 insertions(+), 6 deletions(-) rename exercises/practice/leap/.approaches/{functions => clauses}/content.md (100%) rename exercises/practice/leap/.approaches/{functions => clauses}/snippet.txt (100%) diff --git a/exercises/practice/leap/.approaches/functions/content.md b/exercises/practice/leap/.approaches/clauses/content.md similarity index 100% rename from exercises/practice/leap/.approaches/functions/content.md rename to exercises/practice/leap/.approaches/clauses/content.md diff --git a/exercises/practice/leap/.approaches/functions/snippet.txt b/exercises/practice/leap/.approaches/clauses/snippet.txt similarity index 100% rename from exercises/practice/leap/.approaches/functions/snippet.txt rename to exercises/practice/leap/.approaches/clauses/snippet.txt diff --git a/exercises/practice/leap/.approaches/config.json b/exercises/practice/leap/.approaches/config.json index a8199ca989..07571637a2 100644 --- a/exercises/practice/leap/.approaches/config.json +++ b/exercises/practice/leap/.approaches/config.json @@ -16,9 +16,9 @@ }, { "uuid": "0267853e-9607-4b60-b2f9-e4a34f5316db", - "slug": "functions", + "slug": "clauses", "title": "Multiple clause functions", - "blurb": "Use multiple clause function to control the order of checks.", + "blurb": "Use a multiple clause function to control the order of checks.", "authors": [ "michalporeba" ] diff --git a/exercises/practice/leap/.approaches/flow/content.md b/exercises/practice/leap/.approaches/flow/content.md index 6cc82f0412..8b23cced86 100644 --- a/exercises/practice/leap/.approaches/flow/content.md +++ b/exercises/practice/leap/.approaches/flow/content.md @@ -48,7 +48,7 @@ def leap_year?(year) do end ``` -Similarly to the [functions approach][functions-approach], the order here matters. +Similarly to the [multiple clause function approach][clause-approach], the order here matters. The conditions are evaluated in order, and the first that is not `nil` or `false` leads to the result. ## Case @@ -95,4 +95,4 @@ end [hexdocs-structures]: https://hexdocs.pm/elixir/case-cond-and-if.html [hexdocs-guards]: https://hexdocs.pm/elixir/main/patterns-and-guards.html#guards -[functions-approach]: https://exercism.org/tracks/elixir/exercises/leap/approaches/functions \ No newline at end of file +[clause-approach]: https://exercism.org/tracks/elixir/exercises/leap/approaches/clauses \ No newline at end of file diff --git a/exercises/practice/leap/.approaches/introduction.md b/exercises/practice/leap/.approaches/introduction.md index aeb287926c..378778cf59 100644 --- a/exercises/practice/leap/.approaches/introduction.md +++ b/exercises/practice/leap/.approaches/introduction.md @@ -45,7 +45,7 @@ def leap_year?(year) when rem(year, 4) == 0, do: true def leap_year?(_), do: false ``` -In the [multiple clause function approach][functions-approach] we discuss why in this approach the `Integer.mod/2` function will not work. +In the [multiple clause function approach][clause-approach] we discuss why in this approach the `Integer.mod/2` function will not work. ## Approach: control flow structures @@ -77,7 +77,7 @@ We discuss these and other solutions depending on various control flow structure [mod]: https://hexdocs.pm/elixir/Integer.html#mod/2 [boolean-operators]: https://hexdocs.pm/elixir/operators.html#general-operators [operators-approach]: https://exercism.org/tracks/elixir/exercises/leap/approaches/operators -[functions-approach]: https://exercism.org/tracks/elixir/exercises/leap/approaches/functions +[clause-approach]: https://exercism.org/tracks/elixir/exercises/leap/approaches/clauses [flow-approach]: https://exercism.org/tracks/elixir/exercises/leap/approaches/cond From 16f70347edf76453cbb357782827b03b1e9a2806 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Por=C4=99ba?= Date: Sat, 13 Jan 2024 12:29:55 +0000 Subject: [PATCH 30/33] the number is a divisor --- exercises/practice/leap/.approaches/introduction.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/exercises/practice/leap/.approaches/introduction.md b/exercises/practice/leap/.approaches/introduction.md index 378778cf59..0badaf3845 100644 --- a/exercises/practice/leap/.approaches/introduction.md +++ b/exercises/practice/leap/.approaches/introduction.md @@ -8,8 +8,8 @@ Such operation in computing is called [modulo][modulo]. Unlike many languages, Elixir does not have [operators][operators] for either integer division or modulo. Instead, it provides the [`Kernel.rem/2`][rem] and the [`Integer.mod/2`][mod] functions. -The two functions differ in how they work with negative numbers, but since, in this exercise, -all the numbers are non-negative, both could work, depending on the approach. +The two functions differ in how they work with negative divisors, but since, in this exercise, +all the divisors are non-negative, both could work, depending on the approach you choose. ## General solution From 5c8503c916cc67a2db9a29e0aac0e3f73a51b3af Mon Sep 17 00:00:00 2001 From: Angelika Tyborska Date: Sat, 13 Jan 2024 14:22:09 +0100 Subject: [PATCH 31/33] Reformat code in code blocks --- .../practice/leap/.approaches/clauses/content.md | 4 ++-- .../practice/leap/.approaches/flow/content.md | 10 +++++----- .../practice/leap/.approaches/introduction.md | 14 +++++++------- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/exercises/practice/leap/.approaches/clauses/content.md b/exercises/practice/leap/.approaches/clauses/content.md index 41c0f623d9..b06a00b47f 100644 --- a/exercises/practice/leap/.approaches/clauses/content.md +++ b/exercises/practice/leap/.approaches/clauses/content.md @@ -29,7 +29,7 @@ But because of the order they are evaluated in, they are equivalent to: ```elixir when rem(year, 400) == 0 when rem(year, 100) == 0 and not rem(year, 400) == 0 -when rem(year, 4) == 0 and not rem(year, 100) == 0 and not rem(year, 400) = 0 +when rem(year, 4) == 0 and not rem(year, 100) == 0 and not rem(year, 400) == 0 ``` The final clause, `def leap_year?(_), do: false`, returns false if previous clauses are not a match. @@ -47,4 +47,4 @@ In this approach, the boolean operators matter too. Only the strict ones, `not`, The relaxed `!`, `&&`, `||` will fail to compile. [operators-approach]: https://exercism.org/tracks/elixir/exercises/leap/approaches/operators -[hexdocs-guards]: https://hexdocs.pm/elixir/main/patterns-and-guards.html#guards \ No newline at end of file +[hexdocs-guards]: https://hexdocs.pm/elixir/main/patterns-and-guards.html#guards diff --git a/exercises/practice/leap/.approaches/flow/content.md b/exercises/practice/leap/.approaches/flow/content.md index 8b23cced86..2122227f9d 100644 --- a/exercises/practice/leap/.approaches/flow/content.md +++ b/exercises/practice/leap/.approaches/flow/content.md @@ -84,10 +84,10 @@ Then, pattern matching to tuples is performed. ```elixir def leap_year?(year) do - case { rem(year, 400), rem(year, 100), rem(year, 4) } do - { 0, _, _ } -> true - { _, 0, _ } -> false - { _, _, 0 } -> true + case {rem(year, 400), rem(year, 100), rem(year, 4)} do + {0, _, _} -> true + {_, 0, _} -> false + {_, _, 0} -> true _ -> false end end @@ -95,4 +95,4 @@ end [hexdocs-structures]: https://hexdocs.pm/elixir/case-cond-and-if.html [hexdocs-guards]: https://hexdocs.pm/elixir/main/patterns-and-guards.html#guards -[clause-approach]: https://exercism.org/tracks/elixir/exercises/leap/approaches/clauses \ No newline at end of file +[clause-approach]: https://exercism.org/tracks/elixir/exercises/leap/approaches/clauses diff --git a/exercises/practice/leap/.approaches/introduction.md b/exercises/practice/leap/.approaches/introduction.md index 0badaf3845..1e56f8b458 100644 --- a/exercises/practice/leap/.approaches/introduction.md +++ b/exercises/practice/leap/.approaches/introduction.md @@ -54,18 +54,18 @@ Here are two examples using `if` and `case`. ```elixir if rem(year, 100) == 0 do - rem(year, 400) == 0 + rem(year, 400) == 0 else - rem(year, 4) == 0 + rem(year, 4) == 0 end ``` ```elixir -case { rem(year, 400), rem(year, 100), rem(year, 4) } do - { 0, _, _ } -> true - { _, 0, _ } -> false - { _, _, 0 } -> true - true -> false +case {rem(year, 400), rem(year, 100), rem(year, 4)} do + {0, _, _} -> true + {_, 0, _} -> false + {_, _, 0} -> true + _ -> false end ``` From a2172aecfb5a12445ebbbbd34a27446e4297048a Mon Sep 17 00:00:00 2001 From: Angelika Tyborska Date: Sat, 13 Jan 2024 14:23:20 +0100 Subject: [PATCH 32/33] Run through a grammar checker --- exercises/practice/leap/.approaches/clauses/content.md | 2 +- exercises/practice/leap/.approaches/flow/content.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/exercises/practice/leap/.approaches/clauses/content.md b/exercises/practice/leap/.approaches/clauses/content.md index b06a00b47f..f00ff3261d 100644 --- a/exercises/practice/leap/.approaches/clauses/content.md +++ b/exercises/practice/leap/.approaches/clauses/content.md @@ -39,7 +39,7 @@ The final clause, `def leap_year?(_), do: false`, returns false if previous clau The [guards][hexdocs-guards] are part of the pattern-matching mechanism. They allow for more complex checks of values. However, because of when they are executed to allow the compiler to perform necessary optimization, -only a minimal subset of operations are permitted. +only a minimal subset of operations is permitted. `Kernel.rem/2` is on this limited list, and `Integer.mod/2` is not. This is why, in this approach, only the first one will work, and the latter will not. diff --git a/exercises/practice/leap/.approaches/flow/content.md b/exercises/practice/leap/.approaches/flow/content.md index 2122227f9d..af8c7fca04 100644 --- a/exercises/practice/leap/.approaches/flow/content.md +++ b/exercises/practice/leap/.approaches/flow/content.md @@ -20,8 +20,8 @@ The `if` and `unless` allow to evaluate only one condition. Unlike in many other languages, there is no `else if` option in Elixir. However, in this case, it is not necessary. We can use `if` once to check if the year is divisible by 100. -If it is, then whether it is a leap year or not depends if it is divisible by 400. -If it is not, then whether it is a leap year or not depends if it is divisible by 4. +If it is, then whether it is a leap year or not depends on if it is divisible by 400. +If it is not, then whether it is a leap year or not depends on if it is divisible by 4. ```elixir def leap_year?(year) do From 5a8d6703aba42da60fa1280d7a02f4e98532c1b0 Mon Sep 17 00:00:00 2001 From: Angelika Tyborska Date: Sat, 13 Jan 2024 14:27:21 +0100 Subject: [PATCH 33/33] Format approach snippets --- exercises/practice/leap/.approaches/flow/snippet.txt | 2 +- exercises/practice/leap/.approaches/operators/snippet.txt | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/exercises/practice/leap/.approaches/flow/snippet.txt b/exercises/practice/leap/.approaches/flow/snippet.txt index 22e1a70505..6e304c5ffc 100644 --- a/exercises/practice/leap/.approaches/flow/snippet.txt +++ b/exercises/practice/leap/.approaches/flow/snippet.txt @@ -1,7 +1,7 @@ def leap_year?(year) do if rem(year, 100) == 0 do rem(year, 400) == 0 - else + else rem(year, 4) == 0 end end diff --git a/exercises/practice/leap/.approaches/operators/snippet.txt b/exercises/practice/leap/.approaches/operators/snippet.txt index 50ba418ce3..3014fcd85f 100644 --- a/exercises/practice/leap/.approaches/operators/snippet.txt +++ b/exercises/practice/leap/.approaches/operators/snippet.txt @@ -1,5 +1,5 @@ def leap_year?(year) do - rem(year, 4) == 0 and - not rem(year, 100) == 0 or - rem(year, 400) == 0 + (rem(year, 4) == 0 and + not rem(year, 100) == 0) or + rem(year, 400) == 0 end