Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions site.hs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,12 @@ import Text.Pandoc.Walk as Pandoc (query)
import Text.Pandoc.Shared as Pandoc (stringify)
import Text.Pandoc.Class (runIO)
import Text.Pandoc.Readers.Markdown (readMarkdown)
import Text.Pandoc.Options (readerExtensions, Extension(Ext_implicit_figures), ReaderOptions)
import Text.Pandoc.Options
( Extension (Ext_implicit_figures),
HTMLMathMethod (MathML),
ReaderOptions (readerExtensions),
WriterOptions (writerHTMLMathMethod),
)
import Text.Pandoc.Extensions (disableExtension)
import System.Directory (listDirectory)
import Control.Monad (forM_)
Expand Down Expand Up @@ -187,7 +192,7 @@ chapterCtx mprev mnext =

-- Custom pandoc compiler that uses our custom reader options
customPandocCompiler :: Compiler (Item String)
customPandocCompiler = pandocCompilerWith customReaderOptions defaultHakyllWriterOptions
customPandocCompiler = pandocCompilerWith customReaderOptions customWriterOptions

-- Custom reader options that disable implicit_figures extension
customReaderOptions :: ReaderOptions
Expand All @@ -196,6 +201,12 @@ customReaderOptions = defaultHakyllReaderOptions
(readerExtensions defaultHakyllReaderOptions)
}

customWriterOptions :: WriterOptions
customWriterOptions =
defaultHakyllWriterOptions
{ writerHTMLMathMethod = MathML
}

-- Helper function to pair each element with its previous and next elements
zipPrevNext :: [a] -> [(Maybe a, a, Maybe a)]
zipPrevNext xs = zip3 (Nothing : map Just xs) xs (map Just (drop 1 xs) ++ [Nothing])
16 changes: 8 additions & 8 deletions source_md/higher-order-functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -796,14 +796,14 @@ ghci> scanl (flip (:)) [] [3,2,1]
When using a `scanl`, the final result will be in the last element of the resulting list while a `scanr` will place the result in the head.

Scans are used to monitor the progression of a function that can be implemented as a fold.
Let's answer us this question: **How many elements does it take for the sum of the square roots of all natural numbers to exceed 1000?**
Let's answer us this question: **How many elements does it take for the sum of the square roots of all natural numbers to exceed $1000$?**
To get the square roots of all natural numbers, we just do `map sqrt [1..]`.
Now, to get the sum, we could do a fold, but because we're interested in how the sum progresses, we're going to do a scan.
Once we've done the scan, we just see how many sums are under 1000.
The first sum in the scanlist will be 1, normally.
The second will be 1 plus the square root of 2.
The third will be that plus the square root of 3.
If there are X sums under 1000, then it takes X+1 elements for the sum to exceed 1000.
Once we've done the scan, we just see how many sums are under $1000$.
The first sum in the scanlist will be $1$, normally.
The second will be $1 + \sqrt 2$.
The third will be $1 + \sqrt 2 + \sqrt 3$.
If there are $n$ sums under 1000, then it takes $n + 1$ elements for the sum to exceed $1000$.

```{.haskell:hs}
sqrtSums :: Int
Expand All @@ -820,7 +820,7 @@ ghci> sum (map sqrt [1..130])
```

We use `takeWhile` here instead of `filter` because `filter` doesn't work on infinite lists.
Even though we know the list is ascending, `filter` doesn't, so we use `takeWhile` to cut the scanlist off at the first occurrence of a sum greater than 1000.
Even though we know the list is ascending, `filter` doesn't, so we use `takeWhile` to cut the scanlist off at the first occurrence of a sum greater than $1000$.

## Function application with $ {#function-application}

Expand Down Expand Up @@ -865,7 +865,7 @@ ghci> map ($ 3) [(4+), (10*), (^2), sqrt]

## Function composition {#composition}

In mathematics, function composition is defined like this: ![ (f . g)(x) = f(g(x))](assets/images/higher-order-functions/composition.png), meaning that composing two functions produces a new function that, when called with a parameter, say, *x* is the equivalent of calling *g* with the parameter *x* and then calling the *f* with that result.
In mathematics, function composition is defined like this: $\left( f \circ g \right) (x) = f \left( g(x) \right)$, meaning that composing two functions produces a new function that, when called with an argument, say, $x$ is the equivalent of calling $g$ with the argument $x$ and then calling the $f$ with that result.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do you really need to use \left and \right in these?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, but it looks slightly nicer:
image
Though still not as nice as I'd like. Ideally, the parentheses would share a horizontal symmetry access, and the bigger ones would therefore cross the baseline.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I personally prefer same-sized parenthesis for expressions as simple as these for uniformity sake. I only resort to \left and \right when the expressions are big and it's hard to match the parenthesis. But I don't feel too strong about it in this case.


In Haskell, function composition is pretty much the same thing.
We do function composition with the `.` function, which is defined like so:
Expand Down
2 changes: 1 addition & 1 deletion source_md/modules.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ ghci> transpose ["hey","there","folks"]
["htf","eho","yel","rk","es"]
```

Say we have the polynomials *3x^2^ + 5x + 9*, *10x^3^ + 9* and *8x^3^ + 5x^2^ + x - 1* and we want to add them together.
Say we have the polynomials $3x^2 + 5x + 9$, $10x^3 + 9$ and $8x^3 + 5x^2 + x - 1$ and we want to add them together.
We can use the lists `[0,3,5,9]`, `[10,0,0,9]` and `[8,5,1,-1]` to represent them in Haskell.
Now, to add them, all we have to do is this:

Expand Down
14 changes: 7 additions & 7 deletions source_md/recursion.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,14 @@ Recursion is actually a way of defining functions in which the function is appli
Definitions in mathematics are often given recursively.
For instance, the fibonacci sequence is defined recursively.
First, we define the first two fibonacci numbers non-recursively.
We say that *F(0) = 0* and *F(1) = 1*, meaning that the 0th and 1st fibonacci numbers are 0 and 1, respectively.
We say that $F(0) = 0$ and $F(1) = 1$, meaning that the 0^th^ and 1^st^ fibonacci numbers are $0$ and $1$, respectively.
Then we say that for any other natural number, that fibonacci number is the sum of the previous two fibonacci numbers.
So *F(n) = F(n-1) + F(n-2)*.
That way, *F(3)* is *F(2) + F(1)*, which is *(F(1) + F(0)) + F(1)*.
Because we've now come down to only non-recursively defined fibonacci numbers, we can safely say that *F(3)* is 2.
Having an element or two in a recursion definition defined non-recursively (like *F(0)* and *F(1)* here) is also called the **edge condition** and is important if you want your recursive function to terminate.
If we hadn't defined *F(0)* and *F(1)* non recursively, you'd never get a solution any number because you'd reach 0 and then you'd go into negative numbers.
All of a sudden, you'd be saying that *F(-2000)* is *F(-2001) + F(-2002)* and there still wouldn't be an end in sight!
So $F(n) = F(n-1) + F(n-2)$.
That way, $F(3)$ is $F(2) + F(1)$, which is $(F(1) + F(0)) + F(1)$.
Because we've now come down to only non-recursively defined fibonacci numbers, we can safely say that $F(3)$ is $2$.
Having an element or two in a recursion definition defined non-recursively (like $F(0)$ and $F(1)$ here) is also called the **edge condition** and is important if you want your recursive function to terminate.
If we hadn't defined $F(0)$ and $F(1)$ non recursively, you'd never get a solution any number because you'd reach $0$ and then you'd go into negative numbers.
All of a sudden, you'd be saying that $F(-2000)$ is $F(-2001) + F(-2002)$ and there still wouldn't be an end in sight!

Recursion is important to Haskell because unlike imperative languages, you do computations in Haskell by declaring what something *is* instead of declaring *how* you get it.
That's why there are no while loops or for loops in Haskell and instead we many times have to use recursion to declare what something is.
Expand Down
6 changes: 3 additions & 3 deletions source_md/starting-out.md
Original file line number Diff line number Diff line change
Expand Up @@ -626,8 +626,8 @@ Although it's simpler to just use the `replicate`{.label .function} function if
![frog](assets/images/starting-out/kermit.png){.left width=180 height=156}
If you've ever taken a course in mathematics, you've probably run into *set comprehensions*.
They're normally used for building more specific sets out of general sets.
A basic comprehension for a set that contains the first ten even natural numbers is ![set notation](assets/images/starting-out/setnotation.png).
The part before the pipe is called the output function, `x` is the variable, `N` is the input set and `x <= 10` is the predicate.
A basic comprehension for a set that contains the first ten even natural numbers is $S = \left\{ 2 \cdot x \mid x \in \mathbb N, x \le 10 \right\}$.
The part before the pipe is called the output function, $x$ is the variable, $\mathbb N$ is the input set and $x \le 10$ is the predicate.
That means that the set contains the doubles of all natural numbers that satisfy the predicate.

If we wanted to write that in Haskell, we could do something like `take 10 [2,4..]`.
Expand Down Expand Up @@ -884,7 +884,7 @@ ghci> triangles = [ (a,b,c) | c <- [1..10], a <- [1..10], b <- [1..10] ]
We're just drawing from three lists and our output function is combining them into a triple.
If you evaluate that by typing out `triangles` in GHCi, you'll get a list of all possible triangles with sides under or equal to 10.
Next, we'll add a condition that they all have to be right triangles.
We'll also modify this function by taking into consideration that side *a* isn't larger than the hypotenuse and that side *b* isn't larger than side *a*.
We'll also modify this function by taking into consideration that side $a$ isn't larger than the hypotenuse and that side $b$ isn't larger than side $a$.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is there a good reason to switch from * to $? the former looks simpler to me and I naturally prefer simpler approaches.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, this one is really up to personal preferences.


```{.haskell: .ghci}
ghci> rightTriangles = [ (a,b,c) | c <- [1..10], a <- [1..c], b <- [1..a], a^2 + b^2 == c^2]
Expand Down
2 changes: 1 addition & 1 deletion source_md/syntax-in-functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ When making patterns, we should always include a catch-all pattern so that our p

Pattern matching can also be used on tuples.
What if we wanted to make a function that takes two vectors in a 2D space (that are in the form of pairs) and adds them together?
To add together two vectors, we add their x components separately and then their y components separately.
To add together two vectors, we add their $x$ components separately and then their $y$ components separately.
Here's how we would have done it if we didn't know about pattern matching:

```{.haskell:hs}
Expand Down
Binary file not shown.
Binary file removed static/assets/images/starting-out/setnotation.png
Binary file not shown.