Skip to content

Commit

Permalink
Put <p> tag around contents of hintboxes
Browse files Browse the repository at this point in the history
  • Loading branch information
Gregory Cox committed Mar 16, 2023
1 parent d51af06 commit a2563f0
Show file tree
Hide file tree
Showing 14 changed files with 49 additions and 43 deletions.
12 changes: 6 additions & 6 deletions docs/a-fistful-of-monads.html
Original file line number Diff line number Diff line change
Expand Up @@ -181,12 +181,12 @@ <h2 id="getting-our-feet-wet-with-maybe">Getting our feet wet with Maybe</h2>
monads.
</p>

<div class="hintbox">
<div class="hintbox"><p>
Make sure you understand <a href="functors-applicative-functors-and-monoids.html#applicative-functors">applicatives</a> at this point. It’s good if you have a
feel for how the various <span class="fixed">Applicative</span> instances work
and what kind of computations they represent, because monads are nothing more
than taking our existing applicative knowledge and upgrading it.
</div>
</p></div>

<p>
A value of type <span class="fixed">Maybe a</span> represents a value of type
Expand Down Expand Up @@ -422,12 +422,12 @@ <h2 id="the-monad-type-class">The Monad type class</h2>
<span class="fixed">Just</span>.
</p>

<div class="hintbox">
<div class="hintbox"><p>
Just a reminder: <span class="fixed">return</span> is nothing like the
<span class="fixed">return</span> that’s in most other languages. It doesn’t end
function execution or anything, it just takes a normal value and puts it in a
context.
</div>
</p></div>

<img src="assets/images/a-fistful-of-monads/tur2.png" class="left" width="169" height="145" alt="hmmm yaes">

Expand Down Expand Up @@ -1487,11 +1487,11 @@ <h2 id="the-list-monad">The list monad</h2>
lists) but it does present something as its result.
</p>

<div class="hintbox">
<div class="hintbox"><p>
When you have non-deterministic values interacting, you can view their
computation as a tree where every possible result in a list represents a
separate branch.
</div>
</p></div>

<p>
Here’s the previous expression rewritten in <span class="fixed">do</span> notation:
Expand Down
3 changes: 3 additions & 0 deletions docs/assets/css/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,9 @@ pre.code {
margin-bottom:25px;
background-image:url(https://s3.amazonaws.com/lyah/note.jpg);
}
.hintbox > p {
margin-bottom:0px;
}
.label {
white-space:nowrap;
font-family:Consolas, "Courier New", monospace;
Expand Down
8 changes: 4 additions & 4 deletions docs/for-a-few-monads-more.html
Original file line number Diff line number Diff line change
Expand Up @@ -219,9 +219,9 @@ <h2 id="writer">Writer? I hardly know her!</h2>

<h3 id="monoids-to-the-rescue">Monoids to the rescue</h3>

<div class="hintbox">
<div class="hintbox"><p>
Be sure you know what <a href="functors-applicative-functors-and-monoids.html#monoids">monoids</a> are at this point! Cheers.
</div>
</p></div>

<p>
Right now, <span class="fixed">applyLog</span> takes values of type
Expand Down Expand Up @@ -1203,7 +1203,7 @@ <h2 id="state">Tasteful stateful computations</h2>
<span class="fixed">a</span> the result of the stateful computations.
</p>

<div class="hintbox">
<div class="hintbox"><p>
Assignment in most other languages could be thought of as a stateful
computation. For instance, when we do <span class="fixed">x = 5</span> in an
imperative language, it will usually assign the value
Expand All @@ -1213,7 +1213,7 @@ <h2 id="state">Tasteful stateful computations</h2>
(that is, all the variables that have been assigned previously) and returns a
result (in this case <span class="fixed">5</span>) and a new state, which would
be all the previous variable mappings plus the newly assigned variable.
</div>
</p></div>

<p>
This stateful computation, a function that takes a state
Expand Down
10 changes: 5 additions & 5 deletions docs/functionally-solving-problems.html
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ <h2 id="reverse-polish-notation-calculator">Reverse Polish notation calculator</
<p>Let’s go over the expression <span class="fixed">10 4 3 + 2 * -</span> together! First we push <span class="fixed">10</span> on to the stack and the stack is now <span class="fixed">10</span>. The next item is <span class="fixed">4</span>, so we push it to the stack as well. The stack is now <span class="fixed">10, 4</span>. We do the same with <span class="fixed">3</span> and the stack is now <span class="fixed">10, 4, 3</span>. And now, we encounter an operator, namely <span class="fixed">+</span>! We pop the two top numbers from the stack (so now the stack is just <span class="fixed">10</span>), add those numbers together and push that result to the stack. The stack is now <span class="fixed">10, 7</span>. We push <span class="fixed">2</span> to the stack, the stack for now is <span class="fixed">10, 7, 2</span>. We’ve encountered an operator again, so let’s pop <span class="fixed">7</span> and <span class="fixed">2</span> off the stack, multiply them and push that result to the stack. Multiplying <span class="fixed">7</span> and <span class="fixed">2</span> produces a <span class="fixed">14</span>, so the stack we have now is <span class="fixed">10, 14</span>. Finally, there’s a <span class="fixed">-</span>. We pop <span class="fixed">10</span> and <span class="fixed">14</span> from the stack, subtract <span class="fixed">14</span> from <span class="fixed">10</span> and push that back. The number on the stack is now <span class="fixed">-4</span> and because there are no more numbers or operators in our expression, that’s our result!</p>
<p>Now that we know how we’d calculate any RPN expression by hand, let’s think about how we could make a Haskell function that takes as its parameter a string that contains a RPN expression, like <span class="fixed">"10 4 3 + 2 * -"</span> and gives us back its result.</p>
<p>What would the type of that function be? We want it to take a string as a parameter and produce a number as its result. So it will probably be something like <span class="fixed">solveRPN :: (Num a) =&gt; String -&gt; a</span>.</p>
<div class="hintbox"><strong>Protip:</strong> it really helps to first think what the type declaration of a function should be before concerning ourselves with the implementation and then write it down. In Haskell, a function’s type declaration tells us a whole lot about the function, due to the very strong type system.</div>
<div class="hintbox"><p><strong>Protip:</strong> it really helps to first think what the type declaration of a function should be before concerning ourselves with the implementation and then write it down. In Haskell, a function’s type declaration tells us a whole lot about the function, due to the very strong type system.</p></div>
<img src="assets/images/functionally-solving-problems/calculator.png" class="left" width="220" height="190" alt="HA HA HA">
<p>Cool. When implementing a solution to a problem in Haskell, it’s also good to think back on how you did it by hand and maybe try to see if you can gain any insight from that. Here we see that we treated every number or operator that was separated by a space as a single item. So it might help us if we start by breaking a string like <span class="fixed">"10 4 3 + 2 * -"</span> into a list of items like <span class="fixed">["10","4","3","+","2","*","-"]</span>.</p>
<p>Next up, what did we do with that list of items in our head? We went over it from left to right and kept a stack as we did that. Does the previous sentence remind you of anything? Remember, in the section about <a href="higher-order-functions.html#folds">folds</a>, we said that pretty much any function where you traverse a list from left to right or right to left one element by element and build up (accumulate) some result (whether it’s a number, a list, a stack, whatever) can be implemented with a fold.</p>
Expand Down Expand Up @@ -160,7 +160,7 @@ <h2 id="heathrow-to-london">Heathrow to London</h2>
<p>Alright, can you figure out what the shortest path to the first crossroads (the first blue dot on A, marked <em>A1</em>) on road A is? That’s pretty trivial. We just see if it’s shorter to go directly forward on A or if it’s shorter to go forward on B and then cross over. Obviously, it’s cheaper to go forward via B and then cross over because that takes 40 minutes, whereas going directly via A takes 50 minutes. What about crossroads <em>B1</em>? Same thing. We see that it’s a lot cheaper to just go directly via B (incurring a cost of 10 minutes), because going via A and then crossing over would take us a whole 80 minutes!</p>
<p>Now we know what the cheapest path to <em>A1</em> is (go via B and then cross over, so we’ll say that’s <span class="fixed">B, C</span> with a cost of 40) and we know what the cheapest path to <em>B1</em> is (go directly via B, so that’s just <span class="fixed">B</span>, going at 10). Does this knowledge help us at all if we want to know the cheapest path to the next crossroads on both main roads? Gee golly, it sure does!</p>
<p>Let’s see what the shortest path to <em>A2</em> would be. To get to <em>A2</em>, we’ll either go directly to <em>A2</em> from <em>A1</em> or we’ll go forward from <em>B1</em> and then cross over (remember, we can only move forward or cross to the other side). And because we know the cost to <em>A1</em> and <em>B1</em>, we can easily figure out what the best path to <em>A2</em> is. It costs 40 to get to <em>A1</em> and then 5 to get from <em>A1</em> to <em>A2</em>, so that’s <span class="fixed">B, C, A</span> for a cost of 45. It costs only 10 to get to <em>B1</em>, but then it would take an additional 110 minutes to go to <em>B2</em> and then cross over! So obviously, the cheapest path to <em>A2</em> is <span class="fixed">B, C, A</span>. In the same way, the cheapest way to <em>B2</em> is to go forward from <em>A1</em> and then cross over.</p>
<div class="hintbox"><strong>Maybe you’re asking yourself</strong>: but what about getting to <em>A2</em> by first crossing over at <em>B1</em> and then going on forward? Well, we already covered crossing from <em>B1</em> to <em>A1</em> when we were looking for the best way to <em>A1</em>, so we don’t have to take that into account in the next step as well.</div>
<div class="hintbox"><p><strong>Maybe you’re asking yourself</strong>: but what about getting to <em>A2</em> by first crossing over at <em>B1</em> and then going on forward? Well, we already covered crossing from <em>B1</em> to <em>A1</em> when we were looking for the best way to <em>A1</em>, so we don’t have to take that into account in the next step as well.</p></div>
<p>Now that we have the best path to <em>A2</em> and <em>B2</em>, we can repeat this indefinitely until we reach the end. Once we’ve gotten the best paths for <em>A4</em> and <em>B4</em>, the one that’s cheaper is the optimal path!</p>
<p>So in essence, for the second section, we just repeat the step we did at first, only we take into account what the previous best paths on A and B. We could say that we also took into account the best paths on A and on B in the first step, only they were both empty paths with a cost of 0.</p>
<p>Here’s a summary. To get the best path from Heathrow to London, we do this: first we see what the best path to the next crossroads on main road A is. The two options are going directly forward or starting at the opposite road, going forward and then crossing over. We remember the cost and the path. We use the same method to see what the best path to the next crossroads on main road B is and remember that. Then, we see if the path to the next crossroads on A is cheaper if we go from the previous A crossroads or if we go from the previous B crossroads and then cross over. We remember the cheaper path and then we do the same for the crossroads opposite of it. We do this for every section until we reach the end. Once we’ve reached the end, the cheapest of the two paths that we have is our optimal path!</p>
Expand All @@ -183,7 +183,7 @@ <h2 id="heathrow-to-london">Heathrow to London</h2>
type RoadSystem = [Section]
</pre>
<p>This is pretty much perfect! It’s as simple as it goes and I have a feeling it’ll work perfectly for implementing our solution. <span class="fixed">Section</span> is a simple algebraic data type that holds three integers for the lengths of its three road parts. We introduce a type synonym as well, saying that <span class="fixed">RoadSystem</span> is a list of sections.</p>
<div class="hintbox">We could also use a triple of <span class="fixed">(Int, Int, Int)</span> to represent a road section. Using tuples instead of making your own algebraic data types is good for some small localized stuff, but it’s usually better to make a new type for things like this. It gives the type system more information about what’s what. We can use <span class="fixed">(Int, Int, Int)</span> to represent a road section or a vector in 3D space and we can operate on those two, but that allows us to mix them up. If we use <span class="fixed">Section</span> and <span class="fixed">Vector</span> data types, then we can’t accidentally add a vector to a section of a road system.</div>
<div class="hintbox"><p>We could also use a triple of <span class="fixed">(Int, Int, Int)</span> to represent a road section. Using tuples instead of making your own algebraic data types is good for some small localized stuff, but it’s usually better to make a new type for things like this. It gives the type system more information about what’s what. We can use <span class="fixed">(Int, Int, Int)</span> to represent a road section or a vector in 3D space and we can operate on those two, but that allows us to mix them up. If we use <span class="fixed">Section</span> and <span class="fixed">Vector</span> data types, then we can’t accidentally add a vector to a section of a road system.</p></div>
<p>Our road system from Heathrow to London can now be represented like this:</p>
<pre name="code" class="haskell:hs">
heathrowToLondon :: RoadSystem
Expand All @@ -200,7 +200,7 @@ <h2 id="heathrow-to-london">Heathrow to London</h2>
</pre>
<p>We’re going to have to walk over the list with the sections from left to right and keep the optimal path on A and optimal path on B as we go along. We’ll accumulate the best path as we walk over the list, left to right. What does that sound like? Ding, ding, ding! That’s right, A LEFT FOLD!</p>
<p>When doing the solution by hand, there was a step that we repeated over and over again. It involved checking the optimal paths on A and B so far and the current section to produce the new optimal paths on A and B. For instance, at the beginning the optimal paths were <span class="fixed">[]</span> and <span class="fixed">[]</span> for A and B respectively. We examined the section <span class="fixed">Section 50 10 30</span> and concluded that the new optimal path to <em>A1</em> is <span class="fixed">[(B,10),(C,30)]</span> and the optimal path to <em>B1</em> is <span class="fixed">[(B,10)]</span>. If you look at this step as a function, it takes a pair of paths and a section and produces a new pair of paths. The type is <span class="fixed">(Path, Path) -&gt; Section -&gt; (Path, Path)</span>. Let’s go ahead and implement this function, because it’s bound to be useful.</p>
<div class="hintbox"><strong>Hint:</strong> it will be useful because <span class="fixed">(Path, Path) -&gt; Section -&gt; (Path, Path)</span> can be used as the binary function for a left fold, which has to have a type of <span class="fixed">a -&gt; b -&gt; a</span></div>
<div class="hintbox"><p><strong>Hint:</strong> it will be useful because <span class="fixed">(Path, Path) -&gt; Section -&gt; (Path, Path)</span> can be used as the binary function for a left fold, which has to have a type of <span class="fixed">a -&gt; b -&gt; a</span></p></div>
<pre name="code" class="haskell:hs">
roadStep :: (Path, Path) -&gt; Section -&gt; (Path, Path)
roadStep (pathA, pathB) (Section a b c) =
Expand Down Expand Up @@ -228,7 +228,7 @@ <h2 id="heathrow-to-london">Heathrow to London</h2>
([(C,30),(B,10)],[(B,10)])
</pre>
<p>Remember, the paths are reversed, so read them from right to left. From this we can read that the best path to the next A is to start on B and then cross over to A and that the best path to the next B is to just go directly forward from the starting point at B.</p>
<div class="hintbox"><strong>Optimization tip:</strong> when we do <span class="fixed">priceA = sum $ map snd pathA</span>, we’re calculating the price from the path on every step. We wouldn’t have to do that if we implemented <span class="fixed">roadStep</span> as a <span class="fixed">(Path, Path, Int, Int) -&gt; Section -&gt; (Path, Path, Int, Int)</span> function where the integers represent the best price on A and B.</div>
<div class="hintbox"><p><strong>Optimization tip:</strong> when we do <span class="fixed">priceA = sum $ map snd pathA</span>, we’re calculating the price from the path on every step. We wouldn’t have to do that if we implemented <span class="fixed">roadStep</span> as a <span class="fixed">(Path, Path, Int, Int) -&gt; Section -&gt; (Path, Path, Int, Int)</span> function where the integers represent the best price on A and B.</p></div>
<p>Now that we have a function that takes a pair of paths and a section and produces a new optimal path, we can just easily do a left fold over a list of sections. <span class="fixed">roadStep</span> is called with <span class="fixed">([],[])</span> and the first section and returns a pair of optimal paths to that section. Then, it’s called with that pair of paths and the next section and so on. When we’ve walked over all the sections, we’re left with a pair of optimal paths and the shorter of them is our answer. With this in mind, we can implement <span class="fixed">optimalPath</span>.</p>
<pre name="code" class="haskell:hs">
optimalPath :: RoadSystem -&gt; Path
Expand Down
Loading

0 comments on commit a2563f0

Please sign in to comment.