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
Make sure you understand <ahref="functors-applicative-functors-and-monoids.html#applicative-functors">applicatives</a> at this point. It’s good if you have a
186
186
feel for how the various <spanclass="fixed">Applicative</span> instances work
187
187
and what kind of computations they represent, because monads are nothing more
188
188
than taking our existing applicative knowledge and upgrading it.
189
-
</div>
189
+
</p></div>
190
190
191
191
<p>
192
192
A value of type <spanclass="fixed">Maybe a</span> represents a value of type
@@ -422,12 +422,12 @@ <h2 id="the-monad-type-class">The Monad type class</h2>
422
422
<spanclass="fixed">Just</span>.
423
423
</p>
424
424
425
-
<divclass="hintbox">
425
+
<divclass="hintbox"><p>
426
426
Just a reminder: <spanclass="fixed">return</span> is nothing like the
427
427
<spanclass="fixed">return</span> that’s in most other languages. It doesn’t end
428
428
function execution or anything, it just takes a normal value and puts it in a
<p>Let’s go over the expression <spanclass="fixed">10 4 3 + 2 * -</span> together! First we push <spanclass="fixed">10</span> on to the stack and the stack is now <spanclass="fixed">10</span>. The next item is <spanclass="fixed">4</span>, so we push it to the stack as well. The stack is now <spanclass="fixed">10, 4</span>. We do the same with <spanclass="fixed">3</span> and the stack is now <spanclass="fixed">10, 4, 3</span>. And now, we encounter an operator, namely <spanclass="fixed">+</span>! We pop the two top numbers from the stack (so now the stack is just <spanclass="fixed">10</span>), add those numbers together and push that result to the stack. The stack is now <spanclass="fixed">10, 7</span>. We push <spanclass="fixed">2</span> to the stack, the stack for now is <spanclass="fixed">10, 7, 2</span>. We’ve encountered an operator again, so let’s pop <spanclass="fixed">7</span> and <spanclass="fixed">2</span> off the stack, multiply them and push that result to the stack. Multiplying <spanclass="fixed">7</span> and <spanclass="fixed">2</span> produces a <spanclass="fixed">14</span>, so the stack we have now is <spanclass="fixed">10, 14</span>. Finally, there’s a <spanclass="fixed">-</span>. We pop <spanclass="fixed">10</span> and <spanclass="fixed">14</span> from the stack, subtract <spanclass="fixed">14</span> from <spanclass="fixed">10</span> and push that back. The number on the stack is now <spanclass="fixed">-4</span> and because there are no more numbers or operators in our expression, that’s our result!</p>
41
41
<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 <spanclass="fixed">"10 4 3 + 2 * -"</span> and gives us back its result.</p>
42
42
<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 <spanclass="fixed">solveRPN :: (Num a) => String -> a</span>.</p>
43
-
<divclass="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>
43
+
<divclass="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>
44
44
<imgsrc="assets/images/functionally-solving-problems/calculator.png" class="left" width="220" height="190" alt="HA HA HA">
45
45
<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 <spanclass="fixed">"10 4 3 + 2 * -"</span> into a list of items like <spanclass="fixed">["10","4","3","+","2","*","-"]</span>.</p>
46
46
<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 <ahref="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>
@@ -160,7 +160,7 @@ <h2 id="heathrow-to-london">Heathrow to London</h2>
160
160
<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>
161
161
<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 <spanclass="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 <spanclass="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>
162
162
<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 <spanclass="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 <spanclass="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>
163
-
<divclass="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>
163
+
<divclass="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>
164
164
<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>
165
165
<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>
166
166
<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>
@@ -183,7 +183,7 @@ <h2 id="heathrow-to-london">Heathrow to London</h2>
183
183
type RoadSystem = [Section]
184
184
</pre>
185
185
<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. <spanclass="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 <spanclass="fixed">RoadSystem</span> is a list of sections.</p>
186
-
<divclass="hintbox">We could also use a triple of <spanclass="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 <spanclass="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 <spanclass="fixed">Section</span> and <spanclass="fixed">Vector</span> data types, then we can’t accidentally add a vector to a section of a road system.</div>
186
+
<divclass="hintbox"><p>We could also use a triple of <spanclass="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 <spanclass="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 <spanclass="fixed">Section</span> and <spanclass="fixed">Vector</span> data types, then we can’t accidentally add a vector to a section of a road system.</p></div>
187
187
<p>Our road system from Heathrow to London can now be represented like this:</p>
188
188
<prename="code" class="haskell:hs">
189
189
heathrowToLondon :: RoadSystem
@@ -200,7 +200,7 @@ <h2 id="heathrow-to-london">Heathrow to London</h2>
200
200
</pre>
201
201
<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>
202
202
<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 <spanclass="fixed">[]</span> and <spanclass="fixed">[]</span> for A and B respectively. We examined the section <spanclass="fixed">Section 50 10 30</span> and concluded that the new optimal path to <em>A1</em> is <spanclass="fixed">[(B,10),(C,30)]</span> and the optimal path to <em>B1</em> is <spanclass="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 <spanclass="fixed">(Path, Path) -> Section -> (Path, Path)</span>. Let’s go ahead and implement this function, because it’s bound to be useful.</p>
203
-
<divclass="hintbox"><strong>Hint:</strong> it will be useful because <spanclass="fixed">(Path, Path) -> Section -> (Path, Path)</span> can be used as the binary function for a left fold, which has to have a type of <spanclass="fixed">a -> b -> a</span></div>
203
+
<divclass="hintbox"><p><strong>Hint:</strong> it will be useful because <spanclass="fixed">(Path, Path) -> Section -> (Path, Path)</span> can be used as the binary function for a left fold, which has to have a type of <spanclass="fixed">a -> b -> a</span></p></div>
@@ -228,7 +228,7 @@ <h2 id="heathrow-to-london">Heathrow to London</h2>
228
228
([(C,30),(B,10)],[(B,10)])
229
229
</pre>
230
230
<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>
231
-
<divclass="hintbox"><strong>Optimization tip:</strong> when we do <spanclass="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 <spanclass="fixed">roadStep</span> as a <spanclass="fixed">(Path, Path, Int, Int) -> Section -> (Path, Path, Int, Int)</span> function where the integers represent the best price on A and B.</div>
231
+
<divclass="hintbox"><p><strong>Optimization tip:</strong> when we do <spanclass="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 <spanclass="fixed">roadStep</span> as a <spanclass="fixed">(Path, Path, Int, Int) -> Section -> (Path, Path, Int, Int)</span> function where the integers represent the best price on A and B.</p></div>
232
232
<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. <spanclass="fixed">roadStep</span> is called with <spanclass="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 <spanclass="fixed">optimalPath</span>.</p>
0 commit comments