You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: README.md
+22-5Lines changed: 22 additions & 5 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -28,11 +28,7 @@ After this, the pre-commit hooks will run automatically on each commit to check
28
28
29
29
### Adding Solutions
30
30
31
-
If you want to add solutions to your markdown files in this Jekyll site, follow these steps:
32
-
33
-
### 1. Format Your Solutions Section
34
-
35
-
Ensure that your solutions are marked with a heading that is only the word "Solutions" This can be at any heading level (e.g., `### Solutions`, `#### Solutions`). For example:
31
+
If you want to add solutions to your markdown files in this Jekyll site, you need to separate the solutions into a section. Ensure that your solutions are marked with a heading that is only the word "Solutions". This can be at any heading level (e.g., `### Solutions`, `#### Solutions`). For example:
Do not include any subheadings in solutions. The `wrap_solution` plugin, will automatically process this and hide solutions by default, and will be toggleable on any relevant page.
48
+
49
+
### Adding Alert Boxes
50
+
51
+
To add an alert box:
52
+
53
+
```markdown
54
+
<divclass="alert-box alert-info"markdown="1">
55
+
This is an *important* bit of information!
56
+
</div>
57
+
```
58
+
59
+
Supported alert boxes are `alert-info`, `alert-warning`, and `alert-danger`. To add a heading to the alert box, put the heading in strong emphasis/bold:
60
+
61
+
```markdown
62
+
<divclass="alert-box alert-info"markdown="1">
63
+
**Important Information**
64
+
This is an *important* bit of information!
65
+
</div>
66
+
```
67
+
68
+
The CSS styles will automatically add ‘💡 Note:’, ‘⚠️ Warning:’, or ‘🚨 Important:’ (for the classes `alert-info`, `alert-warning`, and `alert-danger` respectively) in front of the text in bold. Note that this means you cannot use bold text anywhere else in the info box at the moment.
Copy file name to clipboardExpand all lines: _chapters/eithers.md
+18-16Lines changed: 18 additions & 16 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -3,11 +3,15 @@ layout: chapter
3
3
title: "Eithers"
4
4
---
5
5
6
+
<divclass="alert-box alert-info"markdown="1">
7
+
**This is optional reading.**
8
+
</div>
9
+
6
10
## Learning Outcomes
7
11
8
-
- Understand how the `Either` type handles values with two possibilities, typically used for error handling and success cases.
9
-
- Apply the `Functor`, `Applicative`, and `Monad` type classes to the `Either` type, learning how to implement instances for each.
10
-
-Recognize the power of monadic `do` blocks in simplifying code and handling complex workflows.
12
+
- Understand how the `Either` type handles values with two possibilities, typically used for error handling and success cases
13
+
- Apply the `Functor`, `Applicative`, and `Monad` type classes to the `Either` type, learning how to implement instances for each
14
+
-Recognise the power of monadic `do` blocks in simplifying code and handling complex workflows
11
15
12
16
## Introduction to Eithers
13
17
@@ -17,13 +21,13 @@ In Haskell, the `Either` type is used to represent values with two possibilities
17
21
dataEitherab=Lefta | Rightb
18
22
```
19
23
20
-
InHaskell’s `Either` type, convention ([and the official documentation](https://hackage.haskell.org/package/base-4.20.0.1/docs/Data-Either.html)) says errors go on the `Left` and successes on the `Right`.Why?Becauseif it is not right (correct) it must be left.This can be considered another example of bias against the left-handed people around the world, but alas, it is a [cruel world](https://www.youtube.com/watch?v=epvlvDzKfv8).
24
+
InHaskell’s `Either` type, convention ([and the official documentation](https://hackage.haskell.org/package/base-4.20.0.1/docs/Data-Either.html)) says errors go on the `Left` and successes on the `Right`.Why?Becauseif it is not right (correct), it must be left.This can be considered another example of bias against the left-handed people around the world, but alas, it is a [cruel world](https://www.youtube.com/watch?v=epvlvDzKfv8).
21
25
22
-
The `Left`/`Right` convention is also more general then a `Success`/`Error` naming, as `Left` does not always need to be an error, but it is the most common usage.
26
+
The `Left`/`Right` convention is also more general than a `Success`/`Error` naming, as `Left` does not always need to be an error, but it is the most common usage.
23
27
24
28
## Usage of Either
25
29
26
-
We can use `Either` to help us with error catching, similar to a `Maybe` type.However, since the errorcase, has a value, rather than `Nothing`, allowing to store an error message to give information to the programmer/user.
30
+
We can use `Either` to help us with error catching, similar to a `Maybe` type.However, the errorcase has a value rather than `Nothing`, allowing to store an error message to give information to the programmer/user.
27
31
28
32
```haskell
29
33
divide::Double->Double->EitherStringDouble
@@ -61,7 +65,7 @@ Before diving into the `Either` typeclass, let’s briefly recap what kinds are:
61
65
62
66
The `Functor` type class expects a type of kind `* -> *`. For `Either`, this means partially applying the first type parameter, e.g., `instance Functor (Either a)`, where `a` will be the type of the `Left`.
63
67
64
-
We can then define,`fmap` over either, considering `Left` as the error case, and applying the function, when we have a correct (`Right`) case.
68
+
We can then define `fmap` over `Either`, considering `Left` as the error case, and applying the function when we have a correct (`Right`) case.
|nulllines=Left$TransformError"No lines to transform"
160
-
-- Simple transformation, where, we reverse each line.
163
+
-- Simple transformation where we reverse each line.
161
164
|otherwise=Right$mapreverselines
162
165
```
163
166
164
-
The outer `do` block, is using the `IO` monad, while the inner `do` block is using the `Either` monad. This code looks very much like imperative code, using the power of monad to allow for sequencing of operations. However, this is powerful, as it will allow the `Left` error to be threaded through the monadic `do` block, with the user not needing to handle the threading of the error state.
167
+
The outer `do` block is using the `IO` monad, while the inner `do` block is using the `Either` monad. This code looks very much like imperative code, using the power of monads to allow for sequencing of operations. However, this is powerful, as it will allow the `Left` error to be threaded through the monadic `do` block, with the user not needing to handle the threading of the error state.
165
168
166
169
```haskell
167
170
main::IO()
168
171
main =do
169
172
-- Attempt to read the file
170
173
fileResult <- readFileSafe "example.txt"
171
-
172
174
let result =do
173
175
-- Use monad instance to compute sequential operations
174
176
content <- fileResult
175
177
readData <- readData content
176
-
transformData readdData
178
+
transformData readData
177
179
print result
178
180
```
179
181
180
182
## Glossary
181
183
182
-
*Functor*: A type class in Haskell that represents types that can be mapped over. Instances of Functor must define the fmap function, which applies a function to every element in a structure.
184
+
*Functor*: A type class in Haskell that represents types that can be mapped over. Instances of Functor must define the `fmap` function, which applies a function to every element in a structure.
183
185
184
-
*Applicative*: A type class in Haskell that extends Functor, allowing functions that are within a context to be applied to values that are also within a context. Applicative defines the functions `pure` and (`<*>`).
186
+
*Applicative*: A type class in Haskell that extends Functor, allowing functions that are within a context to be applied to values that are also within a context. Applicative defines the functions `pure` and `(<*>)`.
185
187
186
-
*Monad*: A type class in Haskell that represents computations as a series of steps. It provides the bind operation (`>>=`) to chain operations and the return (or `pure`) function to inject values into the monadic context.
188
+
*Monad*: A type class in Haskell that represents computations as a series of steps. It provides the bind operation `(>>=)` to chain operations and the `return` (or `pure`) function to inject values into the monadic context.
However, this exists as four nested streams rather than one continuous flat stream. How do we fix this? We use mergeMap to merge the sub-streams into a single long continuous stream of cards. We now have a lovely little deck of cards :)
However, this is only one deck? How can we create multiple decks. We will create a range, which will create a fixed range of numbers, and for each of those we can create a deck.
All in order, oh no, let us shuffle them. Assuming we have these functions, which can insert an element in to a random position in an array. We will use the reduce, and the randomInsertion to shuffle them.
75
74
@@ -83,25 +82,25 @@ function randomInsert<T>(a:readonly T[],e:T): readonly T[] {
This should be correct? Not quite, we `reduce` to a single value, an array. So, now our stream contains a **single** element, an array, Rather, then being a stream of elements. This array will be all of our cards, shuffled. You can see that as we hover over the element and it attempts to print the contents.
We need to turn this back into a stream. How can we do that, with the power of mergeMap! This will take our list and convert it to a stream, and then flatten it, such that our final result is a long stream of *shuffled* cards.
0 commit comments