From a434b8a434159ca3c4b91d3290ba9481f7dd663e Mon Sep 17 00:00:00 2001 From: Matthijs Blom <19817960+MatthijsBlom@users.noreply.github.com> Date: Tue, 6 Feb 2024 11:24:04 +0100 Subject: [PATCH] Decrease all header levels by one --- .../practice/bob/.approaches/introduction.md | 16 +++++++--------- .../practice/bob/.approaches/string/content.md | 8 +++----- .../practice/bob/.approaches/text/content.md | 10 ++++------ .../.approaches/introduction.md | 8 +++----- .../.approaches/list-of-steps/content.md | 6 ++---- .../.approaches/recursion/content.md | 8 +++----- .../.approaches/worker-wrapper/content.md | 6 ++---- .../practice/hamming/.approaches/introduction.md | 8 +++----- .../hamming/.approaches/recursion/content.md | 8 +++----- .../.approaches/worker-wrapper/content.md | 6 ++---- .../hamming/.approaches/zipwith/content.md | 8 +++----- .../conditional-expression/content.md | 10 ++++------ .../practice/leap/.approaches/guards/content.md | 8 +++----- .../practice/leap/.approaches/introduction.md | 12 +++++------- .../.approaches/logical-expression/content.md | 6 ++---- .../space-age/.approaches/introduction.md | 10 ++++------ 16 files changed, 53 insertions(+), 85 deletions(-) diff --git a/exercises/practice/bob/.approaches/introduction.md b/exercises/practice/bob/.approaches/introduction.md index d340dc151..aba77630a 100644 --- a/exercises/practice/bob/.approaches/introduction.md +++ b/exercises/practice/bob/.approaches/introduction.md @@ -1,12 +1,10 @@ -# Introduction - This problem requires checking against a series of conditions, each associated with a desired output. This suggests using guards. -## General guidance +# General guidance -### Beware partial functions +## Beware partial functions This problem might tempt you into reaching for `last`. However, you should know that it is dangerous: @@ -25,7 +23,7 @@ For this reason, strive to avoid partial functions. It is almost always fairly easy to do so. -### Avoid duplicating code +## Avoid duplicating code At multiple points in your solution you'll need to know whether the query is a question, or yelled. Do not copy–paste the code for determining this. @@ -34,7 +32,7 @@ Instead, give meaningful names to these computations and then use these names to Likewise, if you strip the query, do so only once. -### `where` clauses are your friend! +## `where` clauses are your friend! Giving meaningful names to subexpressions can do wonders for code readability. `where` clauses allow you to list local definitions at the end of the declaration. @@ -48,7 +46,7 @@ More on `where` elsewhere: - Haskell Wiki: [Let vs. Where][haskellwiki-let-vs-where] -### When possible, consider turning functions into constants +## When possible, consider turning functions into constants Many beginning Haskellers write code like @@ -104,7 +102,7 @@ responseFor query ``` -## Approach: using `String` +# Approach: using `String` ```haskell responseFor :: String -> String @@ -126,7 +124,7 @@ It also eschews `last`, which is [partial][wiki-partial-functions], in favor of [Read more about this approach][string]. -## Approach: using `Text` +# Approach: using `Text` ```haskell responseFor :: Text -> Text diff --git a/exercises/practice/bob/.approaches/string/content.md b/exercises/practice/bob/.approaches/string/content.md index c5e96a871..04f42d82b 100644 --- a/exercises/practice/bob/.approaches/string/content.md +++ b/exercises/practice/bob/.approaches/string/content.md @@ -1,5 +1,3 @@ -# Using `String` - ```haskell responseFor :: String -> String responseFor query @@ -18,7 +16,7 @@ This solution uses `any` and `all` to determine whether the query consists entir It also eschews `last`, which is [partial][wiki-partial-functions], in favor of the safe alternative `lastMay`. -## Using dependencies +# Using dependencies The function `lastMay` lives in the `Safe` module of the external `safe` package. To be able to use it, you need to add this package to the list of dependencies in `package.yaml`: @@ -36,7 +34,7 @@ import Safe (lastMay) ``` -## `any` & `all` +# `any` & `all` `any` and `all` are **higher-order functions** that take a predicate (a function that produces a `Boolean`) and a list as arguments. Both check whether elements of the list satisfy the predicate. @@ -113,7 +111,7 @@ And thanks to laziness, `any` and `all` even work on infinite lists! Provided the answer can be determined after looking at finitely many elements, that is. -## In this approach +# In this approach A query is considered silent when it consists entirely of whitespace characters. Which is to say: it is silent when _all_ of its characters are whitespace. diff --git a/exercises/practice/bob/.approaches/text/content.md b/exercises/practice/bob/.approaches/text/content.md index 643ae9471..e055cd029 100644 --- a/exercises/practice/bob/.approaches/text/content.md +++ b/exercises/practice/bob/.approaches/text/content.md @@ -1,5 +1,3 @@ -# Using `Text` - ```haskell responseFor :: Text -> Text responseFor (strip -> query) @@ -19,7 +17,7 @@ This solution works with `Text` instead, which is a data type designed specifica It also employs a _view pattern_. -## Using dependencies +# Using dependencies The `Text` type and associated functions live in the `Data.Text` module of the external `text` package. To be able to use it, you need to add this package to the list of dependencies in `package.yaml`: @@ -41,7 +39,7 @@ import qualified Data.Text as Text ``` -## Language extensions +# Language extensions For various reasons, some of GHC's features are locked behind switches known as _language extensions_. You can enable these by putting so-called _language pragmas_ at the top of your file: @@ -59,7 +57,7 @@ module Bob (responseFor) where ``` -### `OverloadedStrings` +## `OverloadedStrings` By default, `"abc"` is interpreted by the compiler as denoting a `String`. To get a `Text` value instead, you need to explicitly convert using `Text.pack`: @@ -82,7 +80,7 @@ someText = "abc" ``` -### `ViewPatterns` +## `ViewPatterns` Recall, patterns occur in the following positions: diff --git a/exercises/practice/collatz-conjecture/.approaches/introduction.md b/exercises/practice/collatz-conjecture/.approaches/introduction.md index 84b44aa87..6403f77ec 100644 --- a/exercises/practice/collatz-conjecture/.approaches/introduction.md +++ b/exercises/practice/collatz-conjecture/.approaches/introduction.md @@ -1,9 +1,7 @@ -# Introduction - This problem requires iteratively computing the next number in a sequence, until `1` is reached. -## Approach: generate a list of steps +# Approach: generate a list of steps ```haskell -- Using `iterate` @@ -39,7 +37,7 @@ using only functions from the standard library for all of these except one. [Read more about this approach][list-of-steps]. -## Approach: recursion +# Approach: recursion ```haskell collatz :: Integer -> Maybe Integer @@ -54,7 +52,7 @@ While arguably elegant, this approach suffers space usage linear in the number o [Read more about this approach][recursion]. -## Approach: a worker–wrapper construct +# Approach: a worker–wrapper construct ```haskell collatz :: Integer -> Maybe Integer diff --git a/exercises/practice/collatz-conjecture/.approaches/list-of-steps/content.md b/exercises/practice/collatz-conjecture/.approaches/list-of-steps/content.md index 37f2b7c2f..de6e1d780 100644 --- a/exercises/practice/collatz-conjecture/.approaches/list-of-steps/content.md +++ b/exercises/practice/collatz-conjecture/.approaches/list-of-steps/content.md @@ -1,5 +1,3 @@ -# Generate a list of steps - ```haskell -- Using `iterate` collatz :: Integer -> Maybe Integer @@ -32,7 +30,7 @@ This approach neatly disentangles all four concerns of using only functions from the standard library for all of these except one. -## `iterate` and `unfoldr` +# `iterate` and `unfoldr` When you have a 'seed' element and a way of computing every next element from it, you can use `iterate` or `unfoldr` to produce the entire sequence. @@ -79,7 +77,7 @@ iterate :: (a -> a) -> a -> [a] iterate f = unfoldr (\x -> Just (x, f x)) ``` -## In this approach +# In this approach Given any number, `nextStep` will compute the next Collatz number. This is the only logic that is provided by us instead of by the standard library. diff --git a/exercises/practice/collatz-conjecture/.approaches/recursion/content.md b/exercises/practice/collatz-conjecture/.approaches/recursion/content.md index 15f77f271..f8daa6660 100644 --- a/exercises/practice/collatz-conjecture/.approaches/recursion/content.md +++ b/exercises/practice/collatz-conjecture/.approaches/recursion/content.md @@ -1,5 +1,3 @@ -# Recursion - ```haskell collatz :: Integer -> Maybe Integer collatz n = case compare n 1 of @@ -12,7 +10,7 @@ The number of steps it takes to get to `1` is one plus however many more steps i This suggest a recursive solution. -## Recursion +# Recursion [Recursion][wikipedia-recursion] in Haskell is the phenomenon of functions or values being defined in terms of themselves. For example, here is a recursive definition of an (infinite) list: @@ -71,7 +69,7 @@ Haskell does not provide any dedicated loop devices such as many other languages Instead, all 'loopiness' in Haskell is produced through recursion – if not by you then under the hood of some of the functions you use. -## In this approach +# In this approach First, we compare the input with `1`. If it is less than `1` then the input is invalid and we return `Nothing`. @@ -126,7 +124,7 @@ theAnswer = (1 +) <$> collatz (if even n then n `div` 2 else 3 * n + 1) ``` -## Considerations on this approach +# Considerations on this approach In a way, this solution is elegant. However, it suffers an inefficiency. diff --git a/exercises/practice/collatz-conjecture/.approaches/worker-wrapper/content.md b/exercises/practice/collatz-conjecture/.approaches/worker-wrapper/content.md index 79cd1f3e4..fb70dd69c 100644 --- a/exercises/practice/collatz-conjecture/.approaches/worker-wrapper/content.md +++ b/exercises/practice/collatz-conjecture/.approaches/worker-wrapper/content.md @@ -1,5 +1,3 @@ -# Worker–wrapper - ```haskell collatz :: Integer -> Maybe Integer collatz n @@ -14,7 +12,7 @@ This approach uses an inner _worker_ function to simultaneously calculate succes It also uses a _bang pattern_ to force intermediate evaluation, to guarantee decent space efficiency. -## The worker–wrapper construct +# The worker–wrapper construct Sometimes, when solving a problem, it is more convenient or efficient to keep track of some kind of _state_. Many other languages use local variables for this. @@ -95,7 +93,7 @@ The worker–wrapper pattern is more general than demonstrated here. For a few more more examples, see the [relevant wiki article][wiki-worker-wrapper], and for yet more examples and an explanation of the general pattern see the paper «[The worker/wrapper transformation][paper-worker-wrapper]» (pdf). -## Bang patterns +# Bang patterns The above implementation of `length'` _might_ evaluate as efficiently as illustrated. However, depending on which optimization opportunities are spotted by the compiler, it also might not! diff --git a/exercises/practice/hamming/.approaches/introduction.md b/exercises/practice/hamming/.approaches/introduction.md index dd81c39c7..c8200abca 100644 --- a/exercises/practice/hamming/.approaches/introduction.md +++ b/exercises/practice/hamming/.approaches/introduction.md @@ -1,5 +1,3 @@ -# Introduction - To solve this problem, you need to - check that the two inputs have the same length, and @@ -8,7 +6,7 @@ To solve this problem, you need to The desired output is `Nothing` if the inputs are not equally long, and `Just numberOfDifferences` otherwise. -## Approach: `zipWith` +# Approach: `zipWith` ```haskell distance :: String -> String -> Maybe Int @@ -30,7 +28,7 @@ While this style of solution might suffer some inefficiency, it should not be di [Read more about this approach][zipwith] -## Approach: hand-written recursion +# Approach: hand-written recursion ```haskell distance :: String -> String -> Maybe Int @@ -50,7 +48,7 @@ You can use `fmap`/`<$>` for this. [Read more about this approach][recursion] -## Approach: a worker–wrapper construct +# Approach: a worker–wrapper construct ```haskell distance :: String -> String -> Maybe Int diff --git a/exercises/practice/hamming/.approaches/recursion/content.md b/exercises/practice/hamming/.approaches/recursion/content.md index 919751851..6f893dd5b 100644 --- a/exercises/practice/hamming/.approaches/recursion/content.md +++ b/exercises/practice/hamming/.approaches/recursion/content.md @@ -1,5 +1,3 @@ -# Recursion - ```haskell distance :: String -> String -> Maybe Int distance [] [] = Just 0 @@ -8,7 +6,7 @@ distance (x : xs) (y : ys) = distance _ _ = Nothing ``` -## Recursion +# Recursion [Recursion][wikipedia-recursion] in Haskell is the phenomenon of functions or values being defined in terms of themselves. For example, here is a recursive definition of an (infinite) list: @@ -67,7 +65,7 @@ Haskell does not provide any dedicated loop devices such as many other languages Instead, all 'loopiness' in Haskell is produced through recursion – if not by you then under the hood of some of the functions you use. -## In this approach +# In this approach If both inputs are empty, then they are of equal length and they do not have any differing elements, so `Just 0` should be returned. @@ -143,7 +141,7 @@ distance _ _ = Nothing ``` -## Considerations on this approach +# Considerations on this approach In a way, this solution is elegant. However, it suffers an inefficiency. diff --git a/exercises/practice/hamming/.approaches/worker-wrapper/content.md b/exercises/practice/hamming/.approaches/worker-wrapper/content.md index 1a0d0cdfe..3d103c20f 100644 --- a/exercises/practice/hamming/.approaches/worker-wrapper/content.md +++ b/exercises/practice/hamming/.approaches/worker-wrapper/content.md @@ -1,5 +1,3 @@ -# Worker–wrapper - ```haskell distance :: String -> String -> Maybe Int distance = go 0 @@ -13,7 +11,7 @@ This approach uses an inner _worker_ function to simultaneously walk both lists It also uses a _bang pattern_ to force intermediate evaluation, to guarantee decent space efficiency. -## The worker–wrapper construct +# The worker–wrapper construct Sometimes, when solving a problem, it is more convenient or efficient to keep track of some kind of _state_. Many other languages use local variables for this. @@ -94,7 +92,7 @@ The worker–wrapper pattern is more general than demonstrated here. For a few more more examples, see the [relevant wiki article][wiki-worker-wrapper], and for yet more examples and an explanation of the general pattern see the paper «[The worker/wrapper transformation][paper-worker-wrapper]» (pdf). -## Bang patterns +# Bang patterns The above implementation of `length'` _might_ evaluate as efficiently as illustrated. However, depending on which optimization opportunities are spotted by the compiler, it also might not! diff --git a/exercises/practice/hamming/.approaches/zipwith/content.md b/exercises/practice/hamming/.approaches/zipwith/content.md index 69f5e8215..52627eb7f 100644 --- a/exercises/practice/hamming/.approaches/zipwith/content.md +++ b/exercises/practice/hamming/.approaches/zipwith/content.md @@ -1,5 +1,3 @@ -# `zipWith` - ```haskell distance :: String -> String -> Maybe Int distance xs ys @@ -13,7 +11,7 @@ The most straightforward way of solving this problem is to - iterate over both inputs together to count their differences. -## Higher-order functions +# Higher-order functions Higher-order functions are functions that take functions as arguments. Examples well-known even outside of Haskell are `map` and `filter`. @@ -65,7 +63,7 @@ Still other examples include ``` -## In this approach +# In this approach After making sure that the lengths are equal, we count the number of places in which the inputs differ. @@ -125,7 +123,7 @@ distance xs ys ``` -## Considerations on this approach +# Considerations on this approach This style of solution is very easy to understand. This is a very important quality for code to have! diff --git a/exercises/practice/leap/.approaches/conditional-expression/content.md b/exercises/practice/leap/.approaches/conditional-expression/content.md index 99dfbe21f..26ed873ca 100644 --- a/exercises/practice/leap/.approaches/conditional-expression/content.md +++ b/exercises/practice/leap/.approaches/conditional-expression/content.md @@ -1,5 +1,3 @@ -# Conditional expression - ```haskell isLeapYear :: Integer -> Bool isLeapYear year = @@ -11,7 +9,7 @@ isLeapYear year = ``` -## Conditional expressions +# Conditional expressions A _conditional expression_ (`if … then … else …`) is a compound expression that uses a test to determine which of two alternatives to evaluate to. Many other languages feature a similar construct, often termed 'ternary operator'. @@ -39,7 +37,7 @@ _ = case p of ~~~~ -## In this approach +# In this approach This approach uses exactly two tests to determine whether a year is a leap year. @@ -50,7 +48,7 @@ Once we know if the year is a multiple of 100, we know which further test to per - If the year is _not_ evenly divisible by 100, then `divisibleBy 100` is `False` and so the `if` expression evaluates to `divisibleBy 4`. -## When to use `if`? +# When to use `if`? `if` expressions might be a good fit when you @@ -82,7 +80,7 @@ _ = case () of For more on this question, see [Guards vs. if-then-else vs. cases in Haskell][so-guards-if-cases] on StackOverflow. -## An example of lazy evaluation +# An example of lazy evaluation Just like 'ternary operators' in other languages, conditional expressions evaluate lazily. Specifically, only the relevant branch is evaluated: diff --git a/exercises/practice/leap/.approaches/guards/content.md b/exercises/practice/leap/.approaches/guards/content.md index 3b1ea8cce..87ec0239c 100644 --- a/exercises/practice/leap/.approaches/guards/content.md +++ b/exercises/practice/leap/.approaches/guards/content.md @@ -1,5 +1,3 @@ -# Guards - ```haskell isLeapYear :: Integer -> Bool isLeapYear year @@ -11,7 +9,7 @@ isLeapYear year indivisibleBy d = year `mod` d /= 0 ``` -## Guards +# Guards Guards can optionally be added to patterns to constrain when they should match. For example, in @@ -46,7 +44,7 @@ Here there is one fewer pattern, but the first one contains one more guard. Sequences of guards are analogous to `if`–`else if` chains in other languages. -## In this approach +# In this approach When there are not many cases to match against, it is common to use _function definition [syntactic sugar][wikipedia-syntactic-sugar]_ instead of `case` because sometimes that is a bit nicer to read. @@ -121,7 +119,7 @@ This is very similar to the [conditional expression approach][conditional-expres -## When to use guards? +# When to use guards? Many beginning Haskellers write code like diff --git a/exercises/practice/leap/.approaches/introduction.md b/exercises/practice/leap/.approaches/introduction.md index dbb76a34a..b588bcb97 100644 --- a/exercises/practice/leap/.approaches/introduction.md +++ b/exercises/practice/leap/.approaches/introduction.md @@ -1,11 +1,9 @@ -# Introduction - There are various idiomatic approaches to solve Leap. All approaches listed below check for divisibility by 4, 100, and 400. However, they differ in the ways in which they combine these checks. -## Approach: a logical expression +# Approach: a logical expression ```haskell isLeapYear :: Integer -> Bool @@ -17,7 +15,7 @@ isLeapYear year = divisibleBy 4 && (not (divisibleBy 100) || divisibleBy 400) [Read more about this approach][logical-expression]. -## Approach: use guards +# Approach: use guards ```haskell isLeapYear :: Integer -> Bool @@ -33,7 +31,7 @@ isLeapYear year [Read more about this approach][guards]. -## Approach: a conditional expression +# Approach: a conditional expression ```haskell isLeapYear :: Integer -> Bool @@ -48,7 +46,7 @@ isLeapYear year = [Read more about this approach][conditional-expression]. -## General guidance +# General guidance The key to determining whether a given year is a leap year is to know whether the year is evenly divisible by `4`, `100`, and `400`. For determining that, you can use the [`mod` function][mod-function], which yields the remainder after division. @@ -75,7 +73,7 @@ More on `where` and `let` elsewhere: - [`let` and `where` revisited][wikibook-let-vs-where] -## Which approach to use? +# Which approach to use? Code exists primarily for humans to read and reason about. Therefore, in general, go with the approach that _makes the most sense_. diff --git a/exercises/practice/leap/.approaches/logical-expression/content.md b/exercises/practice/leap/.approaches/logical-expression/content.md index 2c99da84d..731ee9587 100644 --- a/exercises/practice/leap/.approaches/logical-expression/content.md +++ b/exercises/practice/leap/.approaches/logical-expression/content.md @@ -1,5 +1,3 @@ -# Logical expression - ```haskell isLeapYear :: Integer -> Bool isLeapYear year = divisibleBy 4 && (not (divisibleBy 100) || divisibleBy 400) @@ -10,7 +8,7 @@ isLeapYear year = divisibleBy 4 && (not (divisibleBy 100) || divisibleBy 400) We can combine smaller logical statements into larger ones using the logical operators `&&` (and), `||` (or), and `not` (negation). -## Precedence +# Precedence In school they teach you that `2 + 3 * 4` is to be read as meaning `2 + (3 * 4)`. This is a convention, chosen for its convenience. @@ -66,7 +64,7 @@ The motivation for the parentheses in the highlighted solution is efficiency; se ~~~~ -## An example of laziness +# An example of laziness Just like in many other languages, Haskell's logical operators display short-circuiting behavior: diff --git a/exercises/practice/space-age/.approaches/introduction.md b/exercises/practice/space-age/.approaches/introduction.md index f19e6f48a..19e5c1995 100644 --- a/exercises/practice/space-age/.approaches/introduction.md +++ b/exercises/practice/space-age/.approaches/introduction.md @@ -1,5 +1,3 @@ -# Introduction - Suppose you are on Mercury. The [orbital period][wikipedia-orbital-period] of Mercury is approximately one fourth of an Earth year. This means that in one Earth year, Mercury will complete about four whole orbits around the sun. @@ -11,7 +9,7 @@ The various planets' orbital periods as compared to the Earth's are given. To convert them from _Earth years_ per orbit to _seconds_ per orbit you need to multiply this by the number of seconds in one Earth year. -## Approach: give meaningful names to important values +# Approach: give meaningful names to important values ```haskell ageOn :: Planet -> Float -> Float @@ -35,9 +33,9 @@ Also a `where` clause is used to give names to important values. This tends to greatly improve readability. -## General guidance +# General guidance -### `where` clauses are your friend! +## `where` clauses are your friend! Giving meaningful names to subexpressions can do wonders for code readability. `let` expressions allow the same. @@ -55,7 +53,7 @@ More on `where` and `let` elsewhere: - [`let` and `where` revisited][wikibook-let-vs-where] -### `case` expressions are also your friend! +## `case` expressions are also your friend! Many beginning Haskellers write code like