1 00:00:00,000 --> 00:00:00,040 2 00:00:00,040 --> 00:00:02,460 The following content is provided under a Creative 3 00:00:02,460 --> 00:00:03,870 Commons license. 4 00:00:03,870 --> 00:00:06,910 Your support will help MIT OpenCourseWare continue to 5 00:00:06,910 --> 00:00:10,560 offer high quality educational resources for free. 6 00:00:10,560 --> 00:00:13,460 To make a donation, or view additional materials from 7 00:00:13,460 --> 00:00:17,390 hundreds of MIT courses, visit MIT OpenCourseWare at 8 00:00:17,390 --> 00:00:18,640 ocw.mit.edu. 9 00:00:18,640 --> 00:00:26,770 10 00:00:26,770 --> 00:00:28,020 PROFESSOR: Hello. 11 00:00:28,020 --> 00:00:32,330 12 00:00:32,330 --> 00:00:34,730 Welcome to the second lecture in 6.01. 13 00:00:34,730 --> 00:00:36,350 I hope you had a good time last week. 14 00:00:36,350 --> 00:00:40,600 15 00:00:40,600 --> 00:00:45,700 Last lecture, we looked at what is probably the most 16 00:00:45,700 --> 00:00:49,680 important theme in this course, which is, how do you 17 00:00:49,680 --> 00:00:53,410 organize your thoughts, your design, the things that you 18 00:00:53,410 --> 00:00:57,720 do, in order to manage complexity when you're trying 19 00:00:57,720 --> 00:01:01,430 to build a complicated system? 20 00:01:01,430 --> 00:01:05,720 The mantra for this class is PCAP-- 21 00:01:05,720 --> 00:01:10,530 primitives, combinations, abstractions, and patterns. 22 00:01:10,530 --> 00:01:14,350 And last time, we saw how at the very most elementary 23 00:01:14,350 --> 00:01:21,880 level, Python provides some tools with which we can 24 00:01:21,880 --> 00:01:27,320 achieve this goal of defining primitives, combining them 25 00:01:27,320 --> 00:01:32,220 into more complicated ideas, abstracting the important 26 00:01:32,220 --> 00:01:36,380 information, and generating and capturing new patterns. 27 00:01:36,380 --> 00:01:40,500 And so, for example, we saw that Python has a defined 28 00:01:40,500 --> 00:01:44,950 statement that lets you associate a sequence of 29 00:01:44,950 --> 00:01:47,070 operations with a name-- 30 00:01:47,070 --> 00:01:49,350 both of those things are important, the sequence 31 00:01:49,350 --> 00:01:53,560 represents a combination, the name represents a way that we 32 00:01:53,560 --> 00:01:56,980 can abstract the behavior of the combination and treat it 33 00:01:56,980 --> 00:02:00,340 as though it were primitive operation. 34 00:02:00,340 --> 00:02:03,360 We saw that we could do the same sort of thing for data 35 00:02:03,360 --> 00:02:05,030 structures. 36 00:02:05,030 --> 00:02:10,590 And in particular, the list structure in Python allows us 37 00:02:10,590 --> 00:02:14,680 to generate hierarchical heterogeneous structures in 38 00:02:14,680 --> 00:02:15,710 much the same way. 39 00:02:15,710 --> 00:02:20,700 Then variables allow us to associate names with those 40 00:02:20,700 --> 00:02:21,850 structures. 41 00:02:21,850 --> 00:02:26,120 And finally, we saw that classes allow us to combine 42 00:02:26,120 --> 00:02:28,090 not only data, but also procedures -- 43 00:02:28,090 --> 00:02:33,550 all into one object of related things. 44 00:02:33,550 --> 00:02:37,840 So that's PCAP at the most primitive level. 45 00:02:37,840 --> 00:02:40,730 What I want to do today is talk about 46 00:02:40,730 --> 00:02:43,210 PCAP at higher levels. 47 00:02:43,210 --> 00:02:47,260 How do you build upon that framework to continue this 48 00:02:47,260 --> 00:02:51,120 idea of building with abstraction and modularity? 49 00:02:51,120 --> 00:02:53,400 How do you make-- 50 00:02:53,400 --> 00:02:56,230 how do you combine primitive operations into powerful 51 00:02:56,230 --> 00:02:56,860 operations? 52 00:02:56,860 --> 00:03:00,830 How do you combine primitive data into powerful data? 53 00:03:00,830 --> 00:03:04,670 And what I want to do is think about the next level above the 54 00:03:04,670 --> 00:03:06,920 most rudimentary level in Python. 55 00:03:06,920 --> 00:03:09,740 So we'll look first at some programming styles, and how 56 00:03:09,740 --> 00:03:14,990 that affects your ability to define useful abstractions. 57 00:03:14,990 --> 00:03:17,590 And then I'll look at something much higher level, 58 00:03:17,590 --> 00:03:19,840 which is state machines, which is the way that we will think 59 00:03:19,840 --> 00:03:22,740 about the construction of robot controls. 60 00:03:22,740 --> 00:03:28,590 61 00:03:28,590 --> 00:03:33,120 So I'll start with just a few words about how you-- 62 00:03:33,120 --> 00:03:35,620 the different ways that you could structure a program. 63 00:03:35,620 --> 00:03:38,280 64 00:03:38,280 --> 00:03:41,580 The reason for doing this is that the basic structure that 65 00:03:41,580 --> 00:03:45,080 you use can have an important effect on 66 00:03:45,080 --> 00:03:48,700 your ability to abstract. 67 00:03:48,700 --> 00:03:53,050 We'll look at three different methodologies for 68 00:03:53,050 --> 00:03:55,420 constructing a program. 69 00:03:55,420 --> 00:04:01,060 I'll refer to the first one as imperative, also procedural. 70 00:04:01,060 --> 00:04:03,370 That's kind of the most basic way you could think about 71 00:04:03,370 --> 00:04:05,220 writing a program. 72 00:04:05,220 --> 00:04:06,940 It's kind of a recipe. 73 00:04:06,940 --> 00:04:09,370 It's kind of like cooking with a recipe. 74 00:04:09,370 --> 00:04:12,710 Take this, add this, stir this, bake for 30 minutes, 75 00:04:12,710 --> 00:04:14,380 that kind of thing. 76 00:04:14,380 --> 00:04:19,329 So if you define a procedure, if you organize the way you 77 00:04:19,329 --> 00:04:22,010 think about it in terms of step by step instructions for, 78 00:04:22,010 --> 00:04:24,070 what should I do next? 79 00:04:24,070 --> 00:04:30,210 We refer to that kind of an approach as imperative. 80 00:04:30,210 --> 00:04:33,340 We'll look at functional programming. 81 00:04:33,340 --> 00:04:36,880 There, even though you implement precisely the same 82 00:04:36,880 --> 00:04:41,340 algorithm, the perspective is a little bit different. 83 00:04:41,340 --> 00:04:45,560 There, rather than focusing quite so narrowly on the step 84 00:04:45,560 --> 00:04:49,560 by step, how do you get from A to B, the idea is going to be, 85 00:04:49,560 --> 00:04:52,700 think about the structure of the problem in terms of 86 00:04:52,700 --> 00:04:56,890 functions in a mathematical sense. 87 00:04:56,890 --> 00:05:01,710 By which I mean, functions that eat inputs, generate 88 00:05:01,710 --> 00:05:04,980 outputs, and don't have side effects. 89 00:05:04,980 --> 00:05:07,450 Side effects are things like setting variables that you can 90 00:05:07,450 --> 00:05:08,700 later look at. 91 00:05:08,700 --> 00:05:10,750 92 00:05:10,750 --> 00:05:13,300 Then I'll look at object-oriented programming. 93 00:05:13,300 --> 00:05:15,990 Again, you could be implementing precisely the 94 00:05:15,990 --> 00:05:19,850 same algorithm by using an object-oriented approach, but 95 00:05:19,850 --> 00:05:24,500 here the focus will be on building collections of data 96 00:05:24,500 --> 00:05:27,650 with procedures that are related, and organizing the 97 00:05:27,650 --> 00:05:31,270 solution to your problem in terms of a hierarchy of such 98 00:05:31,270 --> 00:05:33,210 structures. 99 00:05:33,210 --> 00:05:35,970 So what I'd like to start off today with is to look at an 100 00:05:35,970 --> 00:05:42,790 example problem and how you could program it using any of 101 00:05:42,790 --> 00:05:45,210 these three approaches. 102 00:05:45,210 --> 00:05:48,400 So the example program is going to be, find a sequence 103 00:05:48,400 --> 00:05:49,230 of operations-- 104 00:05:49,230 --> 00:05:52,400 by which I mean, an operation is either 105 00:05:52,400 --> 00:05:53,650 increment or square-- 106 00:05:53,650 --> 00:05:55,890 107 00:05:55,890 --> 00:05:57,990 the idea is that the operations are things that we 108 00:05:57,990 --> 00:06:01,080 will do to integers. 109 00:06:01,080 --> 00:06:03,680 Find a sequence of operations, either increment or square, 110 00:06:03,680 --> 00:06:09,060 that transforms one integer, which is the initial value, i, 111 00:06:09,060 --> 00:06:13,510 into a goal, which I'll call, g. 112 00:06:13,510 --> 00:06:14,990 So I want to think about the problem of 113 00:06:14,990 --> 00:06:16,890 finding such sequences. 114 00:06:16,890 --> 00:06:20,130 So for example, the sequence increment increment increment 115 00:06:20,130 --> 00:06:26,090 square, when applied to 1, would give 16. 116 00:06:26,090 --> 00:06:29,550 So I'm thinking about the first increment increments 1 117 00:06:29,550 --> 00:06:31,560 to give you 2. 118 00:06:31,560 --> 00:06:34,840 The second increment increments 2 to give you 3. 119 00:06:34,840 --> 00:06:38,080 The third increment increments 3 to give you 4. 120 00:06:38,080 --> 00:06:41,290 Then square squares 4 to give you 16. 121 00:06:41,290 --> 00:06:44,130 So I'll refer to this as having found the sequence of 122 00:06:44,130 --> 00:06:47,230 operations, increment increment increment square, 123 00:06:47,230 --> 00:06:51,380 that transforms 1 into 16. 124 00:06:51,380 --> 00:06:53,820 Everybody with me? 125 00:06:53,820 --> 00:06:56,650 OK, I'll be the judge of that. 126 00:06:56,650 --> 00:07:00,770 So, to prove that you're with me, what's the minimum length 127 00:07:00,770 --> 00:07:03,590 sequence of increment and square operations needed to 128 00:07:03,590 --> 00:07:07,010 transform 1 into 100. 129 00:07:07,010 --> 00:07:11,230 You've got thirty seconds to discuss it with your neighbor, 130 00:07:11,230 --> 00:07:13,810 come to an agreement, and I'm gonna ask you to raise your 131 00:07:13,810 --> 00:07:16,680 hands with a number of fingers, (1), (2), (3), (4), 132 00:07:16,680 --> 00:07:18,600 or (5), indicating the right answer. 133 00:07:18,600 --> 00:08:14,900 [AUDIENCE DISCUSSION] 134 00:08:14,900 --> 00:08:17,430 PROFESSOR: OK, everybody raise your hand. 135 00:08:17,430 --> 00:08:19,740 Tell me a number of fingers equal to the right answer, 136 00:08:19,740 --> 00:08:21,245 raise your hand, show me a number of fingers. 137 00:08:21,245 --> 00:08:24,130 138 00:08:24,130 --> 00:08:25,310 OK, I'm seeing-- 139 00:08:25,310 --> 00:08:25,660 OK. 140 00:08:25,660 --> 00:08:28,870 So keep in mind the number of fingers is the 141 00:08:28,870 --> 00:08:30,120 thing before the colon. 142 00:08:30,120 --> 00:08:33,200 143 00:08:33,200 --> 00:08:37,140 That avoids the awkward way of saying less than 4. 144 00:08:37,140 --> 00:08:37,940 OK? 145 00:08:37,940 --> 00:08:40,860 So I want the number before the colon. 146 00:08:40,860 --> 00:08:43,429 So what is the minimum length sequence? 147 00:08:43,429 --> 00:08:46,380 Raise your hand, indicate a number of fingers. 148 00:08:46,380 --> 00:08:49,390 OK, the answers are improving. 149 00:08:49,390 --> 00:08:50,420 Higher so I can see you. 150 00:08:50,420 --> 00:08:53,020 OK, it's about 90% correct, I think. 151 00:08:53,020 --> 00:08:58,850 OK, most people said (3), which is another name for 5. 152 00:08:58,850 --> 00:09:00,100 OK. 153 00:09:00,100 --> 00:09:02,750 154 00:09:02,750 --> 00:09:05,160 So how do you get the answer 5? 155 00:09:05,160 --> 00:09:06,810 What's the answer? 156 00:09:06,810 --> 00:09:08,146 Somebody explain that answer? 157 00:09:08,146 --> 00:09:08,619 Yeah. 158 00:09:08,619 --> 00:09:10,984 AUDIENCE: Increment increment square increment square? 159 00:09:10,984 --> 00:09:12,880 PROFESSOR: That's exactly right. 160 00:09:12,880 --> 00:09:18,060 So since I have two operators, increments and squares, and 161 00:09:18,060 --> 00:09:23,980 since I'm trying to cover a big distance, 1 to 100, square 162 00:09:23,980 --> 00:09:25,130 increases faster-- 163 00:09:25,130 --> 00:09:28,570 at least for bigger numbers, than increment does. 164 00:09:28,570 --> 00:09:30,730 So what you'd like to do is figure out a way of coercing 165 00:09:30,730 --> 00:09:32,380 as many squares as possible. 166 00:09:32,380 --> 00:09:36,230 So a good thing to do is to start at the end, and you can 167 00:09:36,230 --> 00:09:38,990 take the square root of the first one evenly, and that 168 00:09:38,990 --> 00:09:39,950 gives you 10. 169 00:09:39,950 --> 00:09:42,660 But then you can't take the square root of 10, so you back 170 00:09:42,660 --> 00:09:45,420 off and you get 9, and then you can take the square root 171 00:09:45,420 --> 00:09:47,170 of 9, et cetera. 172 00:09:47,170 --> 00:09:49,550 So there's any number of ways you could solve this problem, 173 00:09:49,550 --> 00:09:53,780 the point is, that there's a simple solution which is, the 174 00:09:53,780 --> 00:09:56,920 answer (3), which is a pseudonym for 5. 175 00:09:56,920 --> 00:10:01,930 So 5 operations will get you from 1 to 100. 176 00:10:01,930 --> 00:10:03,480 So what I want to do now-- 177 00:10:03,480 --> 00:10:05,470 now that you know the answer to the question, I want to 178 00:10:05,470 --> 00:10:07,950 write a program to find that answer. 179 00:10:07,950 --> 00:10:10,800 180 00:10:10,800 --> 00:10:13,660 The most straightforward approach that you could use is 181 00:10:13,660 --> 00:10:17,130 what we would call, imperative or procedural. 182 00:10:17,130 --> 00:10:22,600 The idea is to solve the problem by walking your way 183 00:10:22,600 --> 00:10:24,920 through it in some premeditated fashion. 184 00:10:24,920 --> 00:10:27,700 185 00:10:27,700 --> 00:10:31,540 A reasonable premeditated fashion would be, think about 186 00:10:31,540 --> 00:10:36,610 the sequences and order them by length. 187 00:10:36,610 --> 00:10:38,120 Think about all the sequences of length 188 00:10:38,120 --> 00:10:40,630 one, see if they work. 189 00:10:40,630 --> 00:10:41,975 Think about all the sequences of length 190 00:10:41,975 --> 00:10:44,210 two, see if they work. 191 00:10:44,210 --> 00:10:45,620 Three, see if they work. 192 00:10:45,620 --> 00:10:47,710 And just keep going until you find one that works. 193 00:10:47,710 --> 00:10:49,000 That's a very reasonable-- 194 00:10:49,000 --> 00:10:51,210 that's a procedure. 195 00:10:51,210 --> 00:10:55,930 Start by thinking about short sequences, and proceed by 196 00:10:55,930 --> 00:10:58,470 making them longer and longer until you run into one that 197 00:10:58,470 --> 00:11:00,790 happens to solve your problem. 198 00:11:00,790 --> 00:11:02,000 So that's what's going on here. 199 00:11:02,000 --> 00:11:04,940 First I gave a name to the operator, increment. 200 00:11:04,940 --> 00:11:07,230 Then I give a name to the operator, square-- 201 00:11:07,230 --> 00:11:10,620 that's just for convenience. 202 00:11:10,620 --> 00:11:13,140 Then what I want to do is write a program-- 203 00:11:13,140 --> 00:11:16,790 find sequence, that will start at some initial value, say 1, 204 00:11:16,790 --> 00:11:20,090 and go to some goal, say 100. 205 00:11:20,090 --> 00:11:24,890 And the way I'll do that is to enumerate over the lengths of 206 00:11:24,890 --> 00:11:27,180 sequences that are possible -- 207 00:11:27,180 --> 00:11:28,430 1, 2, 3, et cetera. 208 00:11:28,430 --> 00:11:32,100 209 00:11:32,100 --> 00:11:37,080 I'll represent each one of those sequences of operations 210 00:11:37,080 --> 00:11:39,790 by this kind of a representation, I'll make a 211 00:11:39,790 --> 00:11:43,200 tuple that has a string that tells me in 212 00:11:43,200 --> 00:11:46,970 English, what did I do? 213 00:11:46,970 --> 00:11:49,470 And an integer that tells me what the answer is 214 00:11:49,470 --> 00:11:51,530 after I've done that. 215 00:11:51,530 --> 00:11:55,320 So looking ahead, this is the idea-- this is the program 216 00:11:55,320 --> 00:11:57,460 that I'm trying to construct. 217 00:11:57,460 --> 00:12:00,790 I would like the output of the program to start by thinking 218 00:12:00,790 --> 00:12:05,340 about all sequences of length one, then sequences of length 219 00:12:05,340 --> 00:12:07,890 two, then sequences of length three, then sequences of 220 00:12:07,890 --> 00:12:09,140 length four. 221 00:12:09,140 --> 00:12:10,710 222 00:12:10,710 --> 00:12:14,160 For each sequence of length one, I'd like to think about, 223 00:12:14,160 --> 00:12:15,640 what are all the possible sequences? 224 00:12:15,640 --> 00:12:18,490 Well, I could start with 1 and increment it to get 2. 225 00:12:18,490 --> 00:12:21,980 Or I could start with 1 and I could square it to 1. 226 00:12:21,980 --> 00:12:24,790 That's all the possible sequences of length one. 227 00:12:24,790 --> 00:12:27,480 Then I go on to length two, three, four, by the time I'm 228 00:12:27,480 --> 00:12:30,430 down here to length four, I could start with 1, increment 229 00:12:30,430 --> 00:12:34,050 square square increment, and that would give me 17. 230 00:12:34,050 --> 00:12:35,410 That's the structure of the program that 231 00:12:35,410 --> 00:12:36,480 I'm trying to make. 232 00:12:36,480 --> 00:12:37,730 Everybody with it? 233 00:12:37,730 --> 00:12:40,390 234 00:12:40,390 --> 00:12:44,120 So I'm going to define find sequence, I'm going to loop 235 00:12:44,120 --> 00:12:48,370 over all those lengths, I'm going to keep track of all the 236 00:12:48,370 --> 00:12:53,070 different sequences I found as a list of tuples. 237 00:12:53,070 --> 00:12:54,510 After last week you're supposed to be very 238 00:12:54,510 --> 00:12:56,880 comfortable with those kinds of words. 239 00:12:56,880 --> 00:13:00,700 Each one of the sequences is a tuple, a string and a final 240 00:13:00,700 --> 00:13:04,420 value, and the list is all possibilities. 241 00:13:04,420 --> 00:13:06,550 And I'm going to try the ones of length one, then I'm going 242 00:13:06,550 --> 00:13:10,790 to append to each one to make sequences of two, and then I 243 00:13:10,790 --> 00:13:13,440 gonna append to that to make sequences of three, four, 244 00:13:13,440 --> 00:13:15,060 five, and keep on going. 245 00:13:15,060 --> 00:13:20,450 So the point is, that this is a very simple-minded, easy to 246 00:13:20,450 --> 00:13:25,610 conceive recipe for how to search through a large number 247 00:13:25,610 --> 00:13:28,650 of sequences and find the one with the minimum length. 248 00:13:28,650 --> 00:13:32,170 So when you write that program, it iterates down 249 00:13:32,170 --> 00:13:36,550 until it finds number 5, the 5-length sequence here it came 250 00:13:36,550 --> 00:13:41,170 up with the answer 100, so that's the answer. 251 00:13:41,170 --> 00:13:46,090 The point is, that it was an easy way to write the program. 252 00:13:46,090 --> 00:13:49,310 We just think about telling somebody with a pencil and 253 00:13:49,310 --> 00:13:51,680 paper, what would you do? 254 00:13:51,680 --> 00:13:54,320 And we tell Python, rather than the person with the piece 255 00:13:54,320 --> 00:13:57,760 of paper, what to do. 256 00:13:57,760 --> 00:14:00,580 The approach is straightforward. 257 00:14:00,580 --> 00:14:05,560 The only ugliness is that it ended up with 258 00:14:05,560 --> 00:14:09,230 three levels of loops. 259 00:14:09,230 --> 00:14:11,610 And the most common kind of error in this kind of 260 00:14:11,610 --> 00:14:15,330 programming is you just botch the indices. 261 00:14:15,330 --> 00:14:18,370 Because it's got three nested layers of loops, it's very 262 00:14:18,370 --> 00:14:20,120 easy to lose track -- when you're thinking 263 00:14:20,120 --> 00:14:20,880 of layer three -- 264 00:14:20,880 --> 00:14:23,470 about what's happening in layer two. 265 00:14:23,470 --> 00:14:28,190 So that's the only difficulty in this approach. 266 00:14:28,190 --> 00:14:31,920 The challenge is just to keep all the indices consistent. 267 00:14:31,920 --> 00:14:32,540 But it works. 268 00:14:32,540 --> 00:14:34,200 There's nothing wrong with this approach. 269 00:14:34,200 --> 00:14:37,380 It doesn't necessarily lead to the most modular designs, but 270 00:14:37,380 --> 00:14:39,370 you can write functional programs that work this way. 271 00:14:39,370 --> 00:14:42,220 272 00:14:42,220 --> 00:14:46,730 A different way to structure the program, I'll refer it-- 273 00:14:46,730 --> 00:14:49,180 here's a different version of the same program, the same 274 00:14:49,180 --> 00:14:51,910 algorithm, but I'm going to refer to this one as 275 00:14:51,910 --> 00:14:52,740 functional program. 276 00:14:52,740 --> 00:14:56,850 Here the idea is to focus on procedures that implement 277 00:14:56,850 --> 00:15:00,230 functions of a mathematical type. 278 00:15:00,230 --> 00:15:03,310 I want to recast the problem, this time thinking about, how 279 00:15:03,310 --> 00:15:07,480 would I divide it up into functions 280 00:15:07,480 --> 00:15:08,780 that calculate things. 281 00:15:08,780 --> 00:15:13,030 So rather than focusing on, what's the set of nested loops 282 00:15:13,030 --> 00:15:14,980 that I have to make, I want to ask, what would be a 283 00:15:14,980 --> 00:15:17,710 meaningful calculation that I would want to do 284 00:15:17,710 --> 00:15:19,710 to solve this problem? 285 00:15:19,710 --> 00:15:23,140 So the first thing I might do, focusing on this part, I might 286 00:15:23,140 --> 00:15:28,960 write a function, apply, where apply -- 287 00:15:28,960 --> 00:15:31,180 I'm using the methodology of functional programming -- 288 00:15:31,180 --> 00:15:33,120 apply is a pure function. 289 00:15:33,120 --> 00:15:35,780 It's going to eat some inputs, generate an output, and have 290 00:15:35,780 --> 00:15:38,510 no side effects. 291 00:15:38,510 --> 00:15:42,660 So what I want it to do, I want to feed it a list of 292 00:15:42,660 --> 00:15:49,570 functions and ask it, what's the answer? 293 00:15:49,570 --> 00:15:54,640 So apply is going to have as its first argument a list, but 294 00:15:54,640 --> 00:15:59,490 the list is going to be a list of operations. 295 00:15:59,490 --> 00:16:03,120 It's not a list of strings, it's not a list of integers, 296 00:16:03,120 --> 00:16:06,340 it's a list of functions. 297 00:16:06,340 --> 00:16:10,730 And what the procedure apply is going to do is step through 298 00:16:10,730 --> 00:16:14,160 that list, applying the functions 299 00:16:14,160 --> 00:16:15,815 one by one to argument. 300 00:16:15,815 --> 00:16:18,440 301 00:16:18,440 --> 00:16:20,440 So the final goal is written down here. 302 00:16:20,440 --> 00:16:27,180 If I apply nothing to 7, the answer ought to be 7. 303 00:16:27,180 --> 00:16:32,450 If I apply increment to 7, the answer ought to be 8. 304 00:16:32,450 --> 00:16:36,560 If I apply square to 7, the answer ought to be 49. 305 00:16:36,560 --> 00:16:39,580 And if I apply increment square to 7, the 306 00:16:39,580 --> 00:16:40,830 answer ought to be 64. 307 00:16:40,830 --> 00:16:43,380 308 00:16:43,380 --> 00:16:45,280 There's a couple things you're supposed to see here. 309 00:16:45,280 --> 00:16:47,140 First off, apply is a pure function, 310 00:16:47,140 --> 00:16:48,460 it has no side effects. 311 00:16:48,460 --> 00:16:51,180 It eats its input, it does a calculation, it tells you an 312 00:16:51,180 --> 00:16:52,060 answer, and it's done. 313 00:16:52,060 --> 00:16:54,690 There's no extra things that's going on behind your back, 314 00:16:54,690 --> 00:16:57,690 it's not setting a variable, or creating a list, or doing 315 00:16:57,690 --> 00:16:59,000 anything like that. 316 00:16:59,000 --> 00:17:03,440 It has inputs, from those inputs it generates an output, 317 00:17:03,440 --> 00:17:04,690 and that's the end of the story. 318 00:17:04,690 --> 00:17:07,670 319 00:17:07,670 --> 00:17:10,079 Another thing that you should see is that I'm treating 320 00:17:10,079 --> 00:17:13,819 procedures as first-class objects. 321 00:17:13,819 --> 00:17:17,270 That's another tenet of functional programming. 322 00:17:17,270 --> 00:17:23,020 Rather than sending the input to apply as a list of text 323 00:17:23,020 --> 00:17:26,440 strings, or as a list of integers, I'm giving it a list 324 00:17:26,440 --> 00:17:28,590 of function names. 325 00:17:28,590 --> 00:17:31,990 I'm treating functions just as though it were any 326 00:17:31,990 --> 00:17:32,980 other kind of data. 327 00:17:32,980 --> 00:17:35,680 I'm making a list of functions just the same as I could make 328 00:17:35,680 --> 00:17:39,490 a list of integers, or if I made a list of strings, I'm 329 00:17:39,490 --> 00:17:42,310 just making a list of functions. 330 00:17:42,310 --> 00:17:47,300 So another important feature of this program is the idea 331 00:17:47,300 --> 00:17:50,560 that the functions are being treated 332 00:17:50,560 --> 00:17:52,570 as first-class objects. 333 00:17:52,570 --> 00:17:55,070 334 00:17:55,070 --> 00:18:00,580 The next procedure is addLevel. 335 00:18:00,580 --> 00:18:04,090 addLevel is going to be a second pure function. 336 00:18:04,090 --> 00:18:07,170 The idea there is that I'm going to use addLevel to 337 00:18:07,170 --> 00:18:11,780 construct all the different sequences of operations that 338 00:18:11,780 --> 00:18:12,820 are possible. 339 00:18:12,820 --> 00:18:18,910 Each sequence is going to be a list, so the entire-- 340 00:18:18,910 --> 00:18:23,290 all possible sequences will be a list of lists. 341 00:18:23,290 --> 00:18:27,190 So the idea in addLevel was going to be that you take the 342 00:18:27,190 --> 00:18:33,320 list of lists and you generate from that list of lists a new 343 00:18:33,320 --> 00:18:39,930 list of lists that has one more element. 344 00:18:39,930 --> 00:18:44,900 So if the first list of lists had four elements in it, how 345 00:18:44,900 --> 00:18:46,735 many lists are in the second list of lists? 346 00:18:46,735 --> 00:18:50,380 347 00:18:50,380 --> 00:18:51,630 Five. 348 00:18:51,630 --> 00:18:53,770 349 00:18:53,770 --> 00:18:56,400 Four, five? 350 00:18:56,400 --> 00:19:00,390 The first list of lists represents some number of 351 00:19:00,390 --> 00:19:02,600 different sequence of operations. 352 00:19:02,600 --> 00:19:05,550 My second list of lists-- what I want to do is think about 353 00:19:05,550 --> 00:19:07,790 all the different ways that could be extended from a 354 00:19:07,790 --> 00:19:10,370 length-4 sequence to a length-5 sequence. 355 00:19:10,370 --> 00:19:13,090 How many ways can you extend a length-4 sequence to a 356 00:19:13,090 --> 00:19:14,340 length-5 sequence? 357 00:19:14,340 --> 00:19:16,820 358 00:19:16,820 --> 00:19:19,540 Eight. 359 00:19:19,540 --> 00:19:21,080 So four becomes eight. 360 00:19:21,080 --> 00:19:23,645 Why does four become eight? 361 00:19:23,645 --> 00:19:26,020 AUDIENCE: You've got like two possibilities. 362 00:19:26,020 --> 00:19:28,580 PROFESSOR: Because there's two possibilities for the way that 363 00:19:28,580 --> 00:19:29,590 you could extend it. 364 00:19:29,590 --> 00:19:34,260 I could extend the length-4 sequence by adding on an 365 00:19:34,260 --> 00:19:36,850 increment operator, or I could extend it by adding on a 366 00:19:36,850 --> 00:19:38,380 square operator. 367 00:19:38,380 --> 00:19:42,060 So every time I addLevel, it's going to create a new list of 368 00:19:42,060 --> 00:19:45,000 lists with double as many elements in it as 369 00:19:45,000 --> 00:19:46,755 the old list of lists. 370 00:19:46,755 --> 00:19:49,800 Does that make sense? 371 00:19:49,800 --> 00:19:53,330 Other than that, the program works very much the same-- 372 00:19:53,330 --> 00:19:54,410 I should illustrate that. 373 00:19:54,410 --> 00:20:00,170 So addLevel applied to the list of lists, increment. 374 00:20:00,170 --> 00:20:06,340 I'm only considering one sequence of length-1, so how 375 00:20:06,340 --> 00:20:11,090 many ways can I change that if I'm willing to add procedures 376 00:20:11,090 --> 00:20:12,290 increment or square? 377 00:20:12,290 --> 00:20:15,170 Well, I could end up with increment increment by taking 378 00:20:15,170 --> 00:20:16,250 that one and that one. 379 00:20:16,250 --> 00:20:19,680 Or I could end up with increment square by taking 380 00:20:19,680 --> 00:20:20,980 that one and that one. 381 00:20:20,980 --> 00:20:27,580 So if I were to extend the sequence, increment, two 382 00:20:27,580 --> 00:20:30,200 possible ways, by either incrementing again or by 383 00:20:30,200 --> 00:20:33,890 squaring again, I end up with two possibilities represented 384 00:20:33,890 --> 00:20:38,082 by this list of two different lists. 385 00:20:38,082 --> 00:20:39,650 Is that clear? 386 00:20:39,650 --> 00:20:44,980 The important point is that I'm treating functions as any 387 00:20:44,980 --> 00:20:47,835 other kind of data element that could be added to a list. 388 00:20:47,835 --> 00:20:52,960 389 00:20:52,960 --> 00:20:57,180 And when you run that program, you get an answer that's very 390 00:20:57,180 --> 00:21:02,180 similar to the program that we looked at previously, the 391 00:21:02,180 --> 00:21:04,430 imperative program. 392 00:21:04,430 --> 00:21:11,470 Except that the answer now is a list of functions. 393 00:21:11,470 --> 00:21:14,530 So rather than generating a text-string like the previous 394 00:21:14,530 --> 00:21:19,280 example did, this program generates a list as the 395 00:21:19,280 --> 00:21:21,260 answer-- the program generates a list, which 396 00:21:21,260 --> 00:21:22,300 is a list of functions. 397 00:21:22,300 --> 00:21:25,110 The first element in the list is increment, the second 398 00:21:25,110 --> 00:21:27,880 element in the list is the function increment, the third 399 00:21:27,880 --> 00:21:30,540 element is square increment square. 400 00:21:30,540 --> 00:21:32,450 So it gave you the same answer, it just represented it 401 00:21:32,450 --> 00:21:33,690 differently. 402 00:21:33,690 --> 00:21:36,605 Here I'm representing the answer as a list of functions. 403 00:21:36,605 --> 00:21:39,180 404 00:21:39,180 --> 00:21:40,430 That make sense? 405 00:21:40,430 --> 00:21:43,990 406 00:21:43,990 --> 00:21:48,630 So there's a number of advantages to this approach. 407 00:21:48,630 --> 00:21:52,260 One of them is that it kind of automatically coerces you to 408 00:21:52,260 --> 00:21:53,975 think about modules. 409 00:21:53,975 --> 00:21:56,740 410 00:21:56,740 --> 00:21:59,590 By specifically focusing my attention on, how could I 411 00:21:59,590 --> 00:22:04,220 break up that problem by defining functions? 412 00:22:04,220 --> 00:22:06,010 I end up with a bunch of functions 413 00:22:06,010 --> 00:22:11,730 here, apply and addLevel. 414 00:22:11,730 --> 00:22:13,835 And being functions, they're modules. 415 00:22:13,835 --> 00:22:16,810 They are things that are easy to manipulate in other 416 00:22:16,810 --> 00:22:21,430 contexts, and in particular, it's very easy to debug them. 417 00:22:21,430 --> 00:22:25,000 Especially in an interpretive environment like Python. 418 00:22:25,000 --> 00:22:29,220 It's very easy to figure out if your program works by 419 00:22:29,220 --> 00:22:32,330 figuring out if each module works. 420 00:22:32,330 --> 00:22:37,400 That's one of the important features of modular 421 00:22:37,400 --> 00:22:37,910 programming. 422 00:22:37,910 --> 00:22:40,770 When you have a module, it means that you can use that 423 00:22:40,770 --> 00:22:43,790 module in multiple different ways. 424 00:22:43,790 --> 00:22:47,520 It's easy to break apart the debugging problem so that 425 00:22:47,520 --> 00:22:50,200 rather than trying to debug the one, monolithic 426 00:22:50,200 --> 00:22:51,030 structure-- 427 00:22:51,030 --> 00:22:53,990 which was the procedural program that we wrote in the 428 00:22:53,990 --> 00:22:58,720 first part, here we can debug the individual components, 429 00:22:58,720 --> 00:23:00,630 which happen to be functions. 430 00:23:00,630 --> 00:23:03,380 So I can ask, what happens when I apply the 431 00:23:03,380 --> 00:23:04,700 empty list to 7? 432 00:23:04,700 --> 00:23:07,460 Well, my answer better be 7. 433 00:23:07,460 --> 00:23:11,080 So that provides a way of checking. 434 00:23:11,080 --> 00:23:15,430 So one of the features of thinking about the algorithm 435 00:23:15,430 --> 00:23:18,300 as being broken up into a number of functions is the 436 00:23:18,300 --> 00:23:21,520 greater modularity that allows you, for 437 00:23:21,520 --> 00:23:26,060 example, easier debugging. 438 00:23:26,060 --> 00:23:30,810 A much more important reason for thinking this way though, 439 00:23:30,810 --> 00:23:34,800 is the clarity of thought. 440 00:23:34,800 --> 00:23:39,480 And that can be derived from another feature of the 441 00:23:39,480 --> 00:23:42,210 definition of apply. 442 00:23:42,210 --> 00:23:44,950 The particular way I defined apply is 443 00:23:44,950 --> 00:23:48,280 what we call recursive. 444 00:23:48,280 --> 00:23:53,910 It's recursive in the sense that the definition of apply 445 00:23:53,910 --> 00:23:56,780 calls apply. 446 00:23:56,780 --> 00:24:01,530 OK, that sounds like a bad idea, right? 447 00:24:01,530 --> 00:24:06,010 How do I define something in terms of itself? 448 00:24:06,010 --> 00:24:12,570 The idea is that each application, every time apply 449 00:24:12,570 --> 00:24:13,930 calls itself-- 450 00:24:13,930 --> 00:24:17,650 the idea is to structure the procedure so that the new 451 00:24:17,650 --> 00:24:23,070 incarnation is in some sense, simpler than the previous one. 452 00:24:23,070 --> 00:24:26,800 If you can guarantee that, it will reduce the complexity of 453 00:24:26,800 --> 00:24:29,370 the problem from something that you don't know how to 454 00:24:29,370 --> 00:24:32,890 solve, to something that you do know how to solve. 455 00:24:32,890 --> 00:24:36,010 And for that reason, it represents a powerful way to 456 00:24:36,010 --> 00:24:37,320 think about structuring programs. 457 00:24:37,320 --> 00:24:40,410 458 00:24:40,410 --> 00:24:42,570 So as an example of that-- 459 00:24:42,570 --> 00:24:46,510 as an example of structuring programs as recursions, think 460 00:24:46,510 --> 00:24:49,880 about raising a number to a non-negative integer power. 461 00:24:49,880 --> 00:24:54,080 462 00:24:54,080 --> 00:25:01,780 So if I'm trying to raise b to the n, if n is 0, and if n is 463 00:25:01,780 --> 00:25:07,280 a non-negative integer-- well, if n is 0, b to the n is 1. 464 00:25:07,280 --> 00:25:11,830 And if n is a non-negative integer, then b to the n can 465 00:25:11,830 --> 00:25:16,740 be reduced to b times b to the (n minus 1). 466 00:25:16,740 --> 00:25:20,300 Rewriting that functionally, if I say that my function b to 467 00:25:20,300 --> 00:25:24,120 the n can be represented by f of n. 468 00:25:24,120 --> 00:25:26,630 This statement is precisely equivalent to saying that f of 469 00:25:26,630 --> 00:25:34,060 n is 1, if n is 0, or b times f of (n minus 1) if n is 470 00:25:34,060 --> 00:25:36,130 bigger than 0. 471 00:25:36,130 --> 00:25:40,204 So the idea then, is that I may not know how to raise 2 to 472 00:25:40,204 --> 00:25:45,780 the 10th, but I can use the rule to say 2 to the 10th, oh, 473 00:25:45,780 --> 00:25:49,030 that must be 2 times 2 to the 9th. 474 00:25:49,030 --> 00:25:53,100 Great, I don't know how to do 2 to the 9th, either. 475 00:25:53,100 --> 00:25:56,020 But 2 to the 9th is 2 times 2 to the 8th. 476 00:25:56,020 --> 00:26:01,580 And eventually, I boil it down to a case that I do know the 477 00:26:01,580 --> 00:26:05,450 answer to, in particular, b to the 0 is 1. 478 00:26:05,450 --> 00:26:08,750 I would express that idea in Python this way, define 479 00:26:08,750 --> 00:26:11,160 exponent of b, n. 480 00:26:11,160 --> 00:26:13,356 If n is 0, return 1, otherwise return b times exponent of b, 481 00:26:13,356 --> 00:26:14,606 (n minus 1). 482 00:26:14,606 --> 00:26:18,820 483 00:26:18,820 --> 00:26:22,080 OK, so what that does then when you invoke it-- 484 00:26:22,080 --> 00:26:28,910 invoking exponent of 2, 6, in fact, invokes exponent an 485 00:26:28,910 --> 00:26:31,820 additional six times. 486 00:26:31,820 --> 00:26:34,950 487 00:26:34,950 --> 00:26:40,680 If I ask Python to evaluate exponent of 2, 6 it will end 488 00:26:40,680 --> 00:26:44,690 up calling exponent of 2, 5. 489 00:26:44,690 --> 00:26:49,130 But to evaluate that, it will call exponent of 2, 4-- 490 00:26:49,130 --> 00:26:51,150 3, 2, 1, 0. 491 00:26:51,150 --> 00:26:55,320 Then finally, it gets to the base case. 492 00:26:55,320 --> 00:26:59,890 When it gets to the call exponent of 2, 0 it falls into 493 00:26:59,890 --> 00:27:01,840 this case which returns 1 always. 494 00:27:01,840 --> 00:27:04,540 495 00:27:04,540 --> 00:27:09,380 So now exponent of 2, 0 returns 1, but then that can 496 00:27:09,380 --> 00:27:13,050 pick up where call exponent of 2, 1 left off. 497 00:27:13,050 --> 00:27:16,630 When I did 2, 1 it fell into this case, where it was trying 498 00:27:16,630 --> 00:27:21,050 to take 2 times exponent of 2, 0 Now it knows the 499 00:27:21,050 --> 00:27:23,620 answer to 2, 0 is 1. 500 00:27:23,620 --> 00:27:27,340 So I can multiply by 2 and get the answer is 2, and it backs 501 00:27:27,340 --> 00:27:30,900 out then all of the other answers. 502 00:27:30,900 --> 00:27:36,800 So that's an example of how I could use recursion to reduce 503 00:27:36,800 --> 00:27:40,220 a complicated case to a base case-- a simple case that I 504 00:27:40,220 --> 00:27:42,750 know the answer to. 505 00:27:42,750 --> 00:27:48,500 Here, the recruitment with the power of n causes a linear 506 00:27:48,500 --> 00:27:51,940 increase in the number of invocations, so we would call 507 00:27:51,940 --> 00:27:53,480 that a linear process. 508 00:27:53,480 --> 00:27:57,050 So the idea then is that recursion is a good way to 509 00:27:57,050 --> 00:28:02,490 reduce a complicated problem to a simpler problem. 510 00:28:02,490 --> 00:28:05,830 Now that algorithm wasn't particularly fast. 511 00:28:05,830 --> 00:28:09,510 If I imagine doing a big number like 1024. 512 00:28:09,510 --> 00:28:13,680 Raising a number to the 1024 power, that could take awhile. 513 00:28:13,680 --> 00:28:15,031 How long will it take? 514 00:28:15,031 --> 00:28:18,800 515 00:28:18,800 --> 00:28:23,510 1024 is going to-- it will make 1024 calls to reduce it 516 00:28:23,510 --> 00:28:25,200 to the base case. 517 00:28:25,200 --> 00:28:26,650 Here's a way I could speed it up. 518 00:28:26,650 --> 00:28:29,910 519 00:28:29,910 --> 00:28:32,430 Here I'm trying to make something called fast 520 00:28:32,430 --> 00:28:34,580 exponentiation, where I'm going to take advantage of 521 00:28:34,580 --> 00:28:39,050 another rule for the way exponentiation works. 522 00:28:39,050 --> 00:28:43,059 Not only is it true that I can write b to the n as b times b 523 00:28:43,059 --> 00:28:46,820 to the n minus 1, but if n happens to be even, there's 524 00:28:46,820 --> 00:28:50,070 another rule that I can use. 525 00:28:50,070 --> 00:28:54,600 If b is even, then I can raise b to the n over 2, and square 526 00:28:54,600 --> 00:28:56,080 the answer. 527 00:28:56,080 --> 00:29:00,700 OK, that's more knowledge about the way exponents work. 528 00:29:00,700 --> 00:29:03,210 The point is, that when I think about the problem 529 00:29:03,210 --> 00:29:07,610 recursively, when I think about the problem as a 530 00:29:07,610 --> 00:29:11,520 function, there's a natural way to take advantage of that 531 00:29:11,520 --> 00:29:14,170 additional information. 532 00:29:14,170 --> 00:29:18,180 So what I can do then is implement in Python in a 533 00:29:18,180 --> 00:29:20,850 scheme that looks very similar to the one that I used for the 534 00:29:20,850 --> 00:29:24,380 simple exponentiation, but it has a new 535 00:29:24,380 --> 00:29:26,060 rule embedded in there. 536 00:29:26,060 --> 00:29:28,830 So I can say, if n is 0 -- 537 00:29:28,830 --> 00:29:31,340 that was my original base case, if n is 0 538 00:29:31,340 --> 00:29:34,800 the answer is 1. 539 00:29:34,800 --> 00:29:40,250 If the modulus of n when divided by 2 is 1, if it's 540 00:29:40,250 --> 00:29:43,420 odd, use the old rule-- 541 00:29:43,420 --> 00:29:47,470 which says b times the exponent of b, n minus 1. 542 00:29:47,470 --> 00:29:52,390 However, if it's neither 0 nor odd, then use this new rule. 543 00:29:52,390 --> 00:29:57,170 544 00:29:57,170 --> 00:30:00,890 If I use that procedure compared to the previous 545 00:30:00,890 --> 00:30:07,820 program, exponent, how many invocations of fastExponent is 546 00:30:07,820 --> 00:30:10,330 generated by a call to fastExponent of 2, 10? 547 00:30:10,330 --> 00:30:14,010 548 00:30:14,010 --> 00:30:15,810 So talk to your neighbor, figure out an 549 00:30:15,810 --> 00:30:18,310 answer, raise your hand. 550 00:30:18,310 --> 00:30:21,350 Use the number before the dot, just to keep you alert. 551 00:30:21,350 --> 00:31:47,504 [AUDIENCE DISCUSSION] 552 00:31:47,504 --> 00:31:52,010 PROFESSOR: So how many invocations of fastExponent is 553 00:31:52,010 --> 00:31:55,410 generated when you call it with the arguments 2, 10? 554 00:31:55,410 --> 00:31:57,355 Everybody raise your hand, tell me a number of fingers. 555 00:31:57,355 --> 00:32:01,060 556 00:32:01,060 --> 00:32:04,470 OK, it's about 90%, something like that. 557 00:32:04,470 --> 00:32:06,860 The most common answer is five, how did you get five? 558 00:32:06,860 --> 00:32:11,400 559 00:32:11,400 --> 00:32:16,550 So do you think of reducing fastExponent of 2, 10? 560 00:32:16,550 --> 00:32:17,800 What happens the first call? 561 00:32:17,800 --> 00:32:22,208 562 00:32:22,208 --> 00:32:23,684 AUDIENCE: It goes to [UNINTELLIGIBLE] 563 00:32:23,684 --> 00:32:27,128 564 00:32:27,128 --> 00:32:30,080 divided by 2 is 5. 565 00:32:30,080 --> 00:32:32,490 PROFESSOR: So the first thing that happens, is that it 566 00:32:32,490 --> 00:32:37,090 realizes that the 10 is even, so the 10 is not 0, it's not 567 00:32:37,090 --> 00:32:40,390 odd, it goes into this case. 568 00:32:40,390 --> 00:32:43,300 So it tries to run it with 5. 569 00:32:43,300 --> 00:32:45,660 Then when it tries to run fastExponent 570 00:32:45,660 --> 00:32:46,910 with 5, what happens? 571 00:32:46,910 --> 00:32:50,030 572 00:32:50,030 --> 00:32:54,510 OK, so 5 is not 0, so it's not the base case. 573 00:32:54,510 --> 00:33:00,480 It is odd, so 5 gets reduced to 4. 574 00:33:00,480 --> 00:33:03,010 4 gets reduced to 2. 575 00:33:03,010 --> 00:33:05,190 2 gets reduced to-- 576 00:33:05,190 --> 00:33:06,420 et cetera. 577 00:33:06,420 --> 00:33:13,360 So the idea is that we get a faster convergence because, 578 00:33:13,360 --> 00:33:17,500 just like in the very first example we did, we can do two 579 00:33:17,500 --> 00:33:19,940 different kinds of operations-- 580 00:33:19,940 --> 00:33:24,420 either decrement, or in this case half, and half works 581 00:33:24,420 --> 00:33:28,140 faster when the numbers are bigger than decrement does, so 582 00:33:28,140 --> 00:33:32,020 it's the same idea as in that first program. 583 00:33:32,020 --> 00:33:35,010 So the idea, then, is that this requires 5 where we would 584 00:33:35,010 --> 00:33:39,240 have expected in the previous exponent procedure, it would 585 00:33:39,240 --> 00:33:40,940 have required 10. 586 00:33:40,940 --> 00:33:43,880 And that difference just gets bigger and bigger as we make n 587 00:33:43,880 --> 00:33:45,130 bigger and bigger. 588 00:33:45,130 --> 00:33:48,350 589 00:33:48,350 --> 00:33:52,090 Much more importantly though, than the fact that we can make 590 00:33:52,090 --> 00:33:58,630 something fast, is the idea that this is expressive. 591 00:33:58,630 --> 00:34:01,510 The idea is that by structuring the program this 592 00:34:01,510 --> 00:34:06,430 way, it was perfectly obvious how to incorporate more 593 00:34:06,430 --> 00:34:10,449 knowledge about the way exponents work. 594 00:34:10,449 --> 00:34:19,330 I could have done it by using a procedural approach. 595 00:34:19,330 --> 00:34:21,840 Do this, then do this, then do this. 596 00:34:21,840 --> 00:34:24,030 But then I have very complicated indices. 597 00:34:24,030 --> 00:34:26,280 Check if it's-- check if it's squared, check if it's 598 00:34:26,280 --> 00:34:29,210 whatever, and it's inside the loop, right? 599 00:34:29,210 --> 00:34:32,750 So I complicate my looping structure, where here-- 600 00:34:32,750 --> 00:34:35,230 because I'm using the functional approach, it's very 601 00:34:35,230 --> 00:34:39,340 easy to understand that it just introduces another case. 602 00:34:39,340 --> 00:34:40,530 It's nothing complicated. 603 00:34:40,530 --> 00:34:42,909 So it's much more important-- the reason we think about 604 00:34:42,909 --> 00:34:46,250 recursion isn't so much that it's fast, it's because it's 605 00:34:46,250 --> 00:34:48,290 expressive. 606 00:34:48,290 --> 00:34:51,510 It's a way to incorporate knowledge about an answer into 607 00:34:51,510 --> 00:34:53,699 a solution, and that's what we'd like to do. 608 00:34:53,699 --> 00:34:55,020 We want to have a way of making 609 00:34:55,020 --> 00:34:59,310 complicated things simply. 610 00:34:59,310 --> 00:35:05,600 Here's a way to incorporate knowledge about a procedure in 611 00:35:05,600 --> 00:35:07,070 a very straightforward fashion. 612 00:35:07,070 --> 00:35:09,870 All we have is a second case. 613 00:35:09,870 --> 00:35:13,240 Rather than making the loops more complicated, all we have 614 00:35:13,240 --> 00:35:16,060 is a simple new case in this statement. 615 00:35:16,060 --> 00:35:18,490 And that's especially important when you think about 616 00:35:18,490 --> 00:35:20,320 harder problems. 617 00:35:20,320 --> 00:35:22,340 Here is a much harder problem. 618 00:35:22,340 --> 00:35:24,070 So Tower of Hanoi, you probably played 619 00:35:24,070 --> 00:35:25,290 with this as a kid. 620 00:35:25,290 --> 00:35:28,080 I want to transfer all the disks from Post A to Post B-- 621 00:35:28,080 --> 00:35:30,650 I have a typo on your handout, by the way. 622 00:35:30,650 --> 00:35:32,680 I typed C on the handout, and then I wrote the 623 00:35:32,680 --> 00:35:34,730 program the other way. 624 00:35:34,730 --> 00:35:36,090 That should have been a B. 625 00:35:36,090 --> 00:35:38,840 Transfer a stack of disks from Post A to Post B by moving the 626 00:35:38,840 --> 00:35:42,300 disks one at a time, never placing a bigger disk on top 627 00:35:42,300 --> 00:35:43,550 of a smaller disk. 628 00:35:43,550 --> 00:35:47,180 629 00:35:47,180 --> 00:35:50,650 OK, that's kind of a challenging problem. 630 00:35:50,650 --> 00:35:52,620 It's a very challenging problem if you try to 631 00:35:52,620 --> 00:35:54,590 structure it as loops. 632 00:35:54,590 --> 00:35:57,300 If you try to structure it as loops I would recommend that 633 00:35:57,300 --> 00:36:00,080 you do this gazillions of times until you get the 634 00:36:00,080 --> 00:36:02,970 pattern stuck in your head, because the 635 00:36:02,970 --> 00:36:04,220 pattern's not obvious. 636 00:36:04,220 --> 00:36:07,640 637 00:36:07,640 --> 00:36:09,620 But the pattern is obvious if you think 638 00:36:09,620 --> 00:36:10,870 about it as a recursion. 639 00:36:10,870 --> 00:36:13,340 640 00:36:13,340 --> 00:36:18,040 I don't know how to move n from Post A to Post B. How 641 00:36:18,040 --> 00:36:23,850 about this algorithm, take the top n minus 1, move those to 642 00:36:23,850 --> 00:36:25,790 C-- get them out of the way. 643 00:36:25,790 --> 00:36:27,760 I don't know how you're going to do that, but just trust me, 644 00:36:27,760 --> 00:36:29,500 just do it. 645 00:36:29,500 --> 00:36:34,450 So move n minus 1 of them off the top, put them over on C, 646 00:36:34,450 --> 00:36:38,160 that exposes the bottom one. 647 00:36:38,160 --> 00:36:39,390 Move the bottom one to B, which is where 648 00:36:39,390 --> 00:36:41,200 I'd like it to be. 649 00:36:41,200 --> 00:36:44,230 And then by this mysterious process of moving n minus 1, 650 00:36:44,230 --> 00:36:48,586 bring the n minus 1 back from C back on top of B. 651 00:36:48,586 --> 00:36:50,190 OK, what did I just do? 652 00:36:50,190 --> 00:36:52,310 I just started with a problem that I don't 653 00:36:52,310 --> 00:36:54,310 know the answer to. 654 00:36:54,310 --> 00:36:59,040 How do I move n disks from this post to that post? 655 00:36:59,040 --> 00:37:04,420 And I broke it into a sequence of three operations, two of 656 00:37:04,420 --> 00:37:07,790 which I don't know how to do, but one of which I know. 657 00:37:07,790 --> 00:37:10,670 The one will fortuitously be the base case-- 658 00:37:10,670 --> 00:37:12,320 or at least similar to the base case. 659 00:37:12,320 --> 00:37:16,720 So the idea is, if I want to transfer the n, do two 660 00:37:16,720 --> 00:37:21,470 versions of the n minus 1 problem and glue them together 661 00:37:21,470 --> 00:37:24,060 with this middle step. 662 00:37:24,060 --> 00:37:25,810 OK, well I don't know how to do the n minus 1 problem 663 00:37:25,810 --> 00:37:27,730 either, just recurse. 664 00:37:27,730 --> 00:37:28,700 How do I do the n minus 1 one? 665 00:37:28,700 --> 00:37:32,270 Well, I'll do the n minus 2 one. 666 00:37:32,270 --> 00:37:34,210 I don't know how to do that either. 667 00:37:34,210 --> 00:37:37,040 Well, then do the n minus 3 one. 668 00:37:37,040 --> 00:37:39,670 Keep going until I get it down to 1. 669 00:37:39,670 --> 00:37:42,810 Because when I get down to 1, I do know how to move 1. 670 00:37:42,810 --> 00:37:45,370 671 00:37:45,370 --> 00:37:48,200 Does that make sense? 672 00:37:48,200 --> 00:37:51,670 This is supposed to illustrate that the power of recursion is 673 00:37:51,670 --> 00:37:54,240 in thinking. 674 00:37:54,240 --> 00:38:00,840 Some algorithms are easy to describe recursively. 675 00:38:00,840 --> 00:38:06,340 That set, is the set when the hard problem can be reduced to 676 00:38:06,340 --> 00:38:11,280 a problem of the same type that is in some sense simpler. 677 00:38:11,280 --> 00:38:14,320 Here simpler means taking the index n, and turning it 678 00:38:14,320 --> 00:38:17,070 into n minus 1. 679 00:38:17,070 --> 00:38:21,610 If you write this simple little Python snippet and run 680 00:38:21,610 --> 00:38:24,420 it, you get this procedure. 681 00:38:24,420 --> 00:38:25,660 And if you-- 682 00:38:25,660 --> 00:38:28,650 so the procedure means, take the top disk off A, put it on 683 00:38:28,650 --> 00:38:31,860 B. Take the top disk off A, put it on C. Take the top disk 684 00:38:31,860 --> 00:38:34,190 off B, put it on C. 685 00:38:34,190 --> 00:38:37,190 If you do that procedure, it will magically do exactly the 686 00:38:37,190 --> 00:38:39,900 right thing. 687 00:38:39,900 --> 00:38:42,290 If you try to see the pattern here, so that you were to 688 00:38:42,290 --> 00:38:47,120 write this in a procedural approach, the pattern is very 689 00:38:47,120 --> 00:38:52,990 peculiar, but the algorithm for doing it is very simple. 690 00:38:52,990 --> 00:38:53,980 So the idea-- 691 00:38:53,980 --> 00:38:56,910 one of the reasons that we like recursion, is this idea 692 00:38:56,910 --> 00:38:59,170 of expressability. 693 00:38:59,170 --> 00:39:01,860 It makes it easy to express what we're trying to do. 694 00:39:01,860 --> 00:39:05,110 695 00:39:05,110 --> 00:39:09,850 OK, so that's a quick view of the first two ways to do the 696 00:39:09,850 --> 00:39:11,220 first problem that I talked about. 697 00:39:11,220 --> 00:39:13,530 We started thinking about a sequence of operations, either 698 00:39:13,530 --> 00:39:15,010 increment or square, that transforms an 699 00:39:15,010 --> 00:39:19,260 integer i into g. 700 00:39:19,260 --> 00:39:21,380 The first thing we looked at was a procedural approach 701 00:39:21,380 --> 00:39:22,750 where I just gave you a recipe-- 702 00:39:22,750 --> 00:39:24,250 do this, do this, do this. 703 00:39:24,250 --> 00:39:27,280 The issue there is that I ended up with nested loops 704 00:39:27,280 --> 00:39:29,430 three deep. 705 00:39:29,430 --> 00:39:32,490 The issue there is keeping track of the indices for all 706 00:39:32,490 --> 00:39:33,240 of the different loops. 707 00:39:33,240 --> 00:39:35,900 We just talked about a functional approach. 708 00:39:35,900 --> 00:39:42,030 That can have an advantage, especially whenever the 709 00:39:42,030 --> 00:39:46,450 functional approach has a very simple implementation. 710 00:39:46,450 --> 00:39:48,780 The last approach I want to talk about very briefly is 711 00:39:48,780 --> 00:39:50,870 object-oriented approach. 712 00:39:50,870 --> 00:39:52,490 Here-- 713 00:39:52,490 --> 00:39:54,450 I'm doing the same problem again, find the sequence of 714 00:39:54,450 --> 00:39:59,210 operations that transforms i into g, 1 into 100. 715 00:39:59,210 --> 00:40:01,740 Here I'm doing the same algorithm again. 716 00:40:01,740 --> 00:40:04,500 I mean, I haven't really changed the algorithm in going 717 00:40:04,500 --> 00:40:07,260 from the procedural approach to the functional approach, to 718 00:40:07,260 --> 00:40:09,010 here, the object-oriented approach. 719 00:40:09,010 --> 00:40:11,770 I have changed the representation of the program, 720 00:40:11,770 --> 00:40:14,200 and that's the point. 721 00:40:14,200 --> 00:40:15,780 Here the representation of the program 722 00:40:15,780 --> 00:40:18,480 is in terms of objects. 723 00:40:18,480 --> 00:40:22,080 Here what I'm going to do is think about organizing all the 724 00:40:22,080 --> 00:40:26,750 sequences of operations that are possible in a tree. 725 00:40:26,750 --> 00:40:30,180 So the sequences that I could do, I could do no operation 726 00:40:30,180 --> 00:40:33,100 followed by increment increment increment. 727 00:40:33,100 --> 00:40:36,580 Or I could do nothing increment increment square. 728 00:40:36,580 --> 00:40:39,610 Or I could do nothing square increment square. 729 00:40:39,610 --> 00:40:41,880 So I'm thinking about all the possible sequences, but this 730 00:40:41,880 --> 00:40:46,780 time, I'm not thinking about it is a text-string, I'm not 731 00:40:46,780 --> 00:40:49,670 thinking about it as a list of functions that I need to call. 732 00:40:49,670 --> 00:40:56,740 I'm thinking about it as this tree, this tree of objects. 733 00:40:56,740 --> 00:40:59,350 And in the object-oriented approach, what I'm going to do 734 00:40:59,350 --> 00:41:04,290 is think about the solution in terms of building up the tree 735 00:41:04,290 --> 00:41:07,530 until I find the answer. 736 00:41:07,530 --> 00:41:10,250 So the key in the object-oriented approach is to 737 00:41:10,250 --> 00:41:13,355 think of a useful object. 738 00:41:13,355 --> 00:41:18,050 What would I like to remember when I'm constructing the 739 00:41:18,050 --> 00:41:21,460 solution as this kind of a tree? 740 00:41:21,460 --> 00:41:29,770 Well, if I call every circle a node, I can define a class 741 00:41:29,770 --> 00:41:31,750 that will keep track of all the important 742 00:41:31,750 --> 00:41:33,940 things about each node. 743 00:41:33,940 --> 00:41:39,790 And then I can structure my program as creating nodes, 744 00:41:39,790 --> 00:41:44,560 connecting them up into that tree, and 745 00:41:44,560 --> 00:41:46,260 looking for the answer. 746 00:41:46,260 --> 00:41:48,685 So each one of these nodes, each one of these circles, 747 00:41:48,685 --> 00:41:57,220 ought to have a parent, they ought to have an action, and 748 00:41:57,220 --> 00:41:59,500 they ought to have an answer. 749 00:41:59,500 --> 00:42:03,160 So, for example, let's say that I started with the 750 00:42:03,160 --> 00:42:06,750 initial value i equals 1. 751 00:42:06,750 --> 00:42:11,930 Then this node right here might say, whatever your 752 00:42:11,930 --> 00:42:15,580 answer was at this point, the answer here was 1. 753 00:42:15,580 --> 00:42:19,210 So the answer here is going to be 1 after it's been 754 00:42:19,210 --> 00:42:22,070 incremented, so answer should be 2. 755 00:42:22,070 --> 00:42:23,845 So associated with each one of these nodes is 756 00:42:23,845 --> 00:42:24,880 going to be a parent. 757 00:42:24,880 --> 00:42:27,300 The parent of this guy is this guy, the parent of this guy is 758 00:42:27,300 --> 00:42:30,730 this guy, the parent of this guy is that guy. 759 00:42:30,730 --> 00:42:33,710 Associated with each node is going to be an action. 760 00:42:33,710 --> 00:42:36,090 When I'm here, my action is to increment. 761 00:42:36,090 --> 00:42:40,210 When I'm here, my action is to square. 762 00:42:40,210 --> 00:42:43,600 And associated with each node is going to be the answer. 763 00:42:43,600 --> 00:42:47,420 So if I started at 1, by the time I get here, the answer's 764 00:42:47,420 --> 00:42:51,025 going to be 2, 4, 16. 765 00:42:51,025 --> 00:42:55,040 766 00:42:55,040 --> 00:42:57,050 So the idea is that I'm structuring the 767 00:42:57,050 --> 00:42:59,870 problem as a tree. 768 00:42:59,870 --> 00:43:02,570 Each node has a couple things it wants to remember, it wants 769 00:43:02,570 --> 00:43:04,260 to know who it's parent was. 770 00:43:04,260 --> 00:43:06,060 It wants to know, what's the operation 771 00:43:06,060 --> 00:43:07,840 associated with this node? 772 00:43:07,840 --> 00:43:10,190 And it wants to know the answer at this node. 773 00:43:10,190 --> 00:43:12,760 774 00:43:12,760 --> 00:43:16,220 Also associated with each node, a method. 775 00:43:16,220 --> 00:43:19,220 And the method will be to print out the answer if this 776 00:43:19,220 --> 00:43:21,150 node is the answer. 777 00:43:21,150 --> 00:43:25,010 So the print routine is going to have to say, OK, I ended up 778 00:43:25,010 --> 00:43:26,760 here and that happens to be the answer. 779 00:43:26,760 --> 00:43:27,760 Well, how did I get here? 780 00:43:27,760 --> 00:43:30,610 Well, I have a parent, who has a parent, who has a parent, 781 00:43:30,610 --> 00:43:33,020 who is none. 782 00:43:33,020 --> 00:43:36,960 So this routine is supposed to figure out the sequence of 783 00:43:36,960 --> 00:43:39,500 operations that led me from the initial value up at the 784 00:43:39,500 --> 00:43:44,655 top to the final answer that just happens to be goal. 785 00:43:44,655 --> 00:43:46,980 Is that clear? 786 00:43:46,980 --> 00:43:51,720 So then I structure the program in terms of building 787 00:43:51,720 --> 00:43:53,540 those node structures. 788 00:43:53,540 --> 00:43:57,390 I start off by making a node, which is the top node. 789 00:43:57,390 --> 00:44:00,570 It has no parent, it has no action, and the answer to the 790 00:44:00,570 --> 00:44:03,570 top node is 1. 791 00:44:03,570 --> 00:44:06,510 And then I just think through loops that are very similar to 792 00:44:06,510 --> 00:44:10,750 the loops that I was using before. 793 00:44:10,750 --> 00:44:14,260 They're structured similarly to the way they were 794 00:44:14,260 --> 00:44:19,460 structured in the case of the imperative program, except now 795 00:44:19,460 --> 00:44:23,420 the iterations are generating new nodes. 796 00:44:23,420 --> 00:44:27,320 The iterations are simpler, because each one just 797 00:44:27,320 --> 00:44:28,210 generates a node. 798 00:44:28,210 --> 00:44:30,540 It's not like in the imperative case where I 799 00:44:30,540 --> 00:44:34,110 treated separately, what was the ASCII string that 800 00:44:34,110 --> 00:44:38,100 represented the answer, and what was 801 00:44:38,100 --> 00:44:40,460 the cumulative answer? 802 00:44:40,460 --> 00:44:43,240 Here I don't have two pieces of things that I need to do 803 00:44:43,240 --> 00:44:46,660 inside my loop, I just make a node. 804 00:44:46,660 --> 00:44:49,930 So the idea is that when I solve the problem using this 805 00:44:49,930 --> 00:44:53,200 approach, what I'm trying to do is build a representation 806 00:44:53,200 --> 00:44:55,680 for the solution out of pieces that make 807 00:44:55,680 --> 00:44:56,930 sense for this problem. 808 00:44:56,930 --> 00:45:01,750 809 00:45:01,750 --> 00:45:05,970 So the important idea that I want to get across was to 810 00:45:05,970 --> 00:45:10,410 think about modularity at the next higher level. 811 00:45:10,410 --> 00:45:13,620 We started last time with modularity at the most 812 00:45:13,620 --> 00:45:17,310 microscopic level in Python, and we saw how Python had 813 00:45:17,310 --> 00:45:21,800 primitives that allowed us to build more complicated 814 00:45:21,800 --> 00:45:23,850 structures and simplified our task of 815 00:45:23,850 --> 00:45:26,690 understanding complex designs. 816 00:45:26,690 --> 00:45:28,270 We looked at the most primitive level 817 00:45:28,270 --> 00:45:29,730 in the first lecture. 818 00:45:29,730 --> 00:45:32,970 What I just went over was how even within the structure of 819 00:45:32,970 --> 00:45:36,400 Python, you can structure programs that are 820 00:45:36,400 --> 00:45:39,370 more or less modular. 821 00:45:39,370 --> 00:45:42,270 And the important point is that the way you structure the 822 00:45:42,270 --> 00:45:49,050 program influences the degree of modularity that you get. 823 00:45:49,050 --> 00:45:53,220 So the structure of the program has a significant 824 00:45:53,220 --> 00:45:58,450 effect on how modular your solution is. 825 00:45:58,450 --> 00:46:01,280 826 00:46:01,280 --> 00:46:05,080 What I want to do for the rest of the time today is jump one 827 00:46:05,080 --> 00:46:07,540 higher level yet. 828 00:46:07,540 --> 00:46:10,790 So last time, primitives within Python. 829 00:46:10,790 --> 00:46:15,970 First half of this hour, imperative programming, 830 00:46:15,970 --> 00:46:18,410 functional programming, object-oriented programming, 831 00:46:18,410 --> 00:46:21,420 approaches that affect the modularity of your solution. 832 00:46:21,420 --> 00:46:25,620 Now I want to go up one more level and think about 833 00:46:25,620 --> 00:46:29,630 abstraction and modularity at a much higher level. 834 00:46:29,630 --> 00:46:32,820 And there, I'm going to think about programs that control 835 00:46:32,820 --> 00:46:34,830 the evolution of processes. 836 00:46:34,830 --> 00:46:35,580 What's a process? 837 00:46:35,580 --> 00:46:39,710 A process is some set of procedures 838 00:46:39,710 --> 00:46:41,620 that evolve over time. 839 00:46:41,620 --> 00:46:42,890 An example was a bank account. 840 00:46:42,890 --> 00:46:45,540 841 00:46:45,540 --> 00:46:48,180 OK, with the problems that we've been thinking about so 842 00:46:48,180 --> 00:46:49,910 far, there was a clear answer. 843 00:46:49,910 --> 00:46:51,195 What's the minimum-length sequence 844 00:46:51,195 --> 00:46:52,470 that blah, blah, blah. 845 00:46:52,470 --> 00:46:52,700 Right? 846 00:46:52,700 --> 00:46:54,640 There was a clear answer to that problem. 847 00:46:54,640 --> 00:46:58,200 Here there isn't a clear answer to the problem, what's 848 00:46:58,200 --> 00:47:01,020 the answer to the bank account? 849 00:47:01,020 --> 00:47:04,710 The bank represents a process, it's something that 850 00:47:04,710 --> 00:47:05,980 changes with time. 851 00:47:05,980 --> 00:47:08,560 There are transactions. 852 00:47:08,560 --> 00:47:11,070 Every time you make a deposit or a withdrawal, you do a 853 00:47:11,070 --> 00:47:16,170 transaction that causes some action to happen in the bank. 854 00:47:16,170 --> 00:47:20,260 So there isn't an answer, there's an evolving answer. 855 00:47:20,260 --> 00:47:21,890 So those are the kinds of problems I want 856 00:47:21,890 --> 00:47:24,070 to think about now. 857 00:47:24,070 --> 00:47:26,020 Graphical user interfaces. 858 00:47:26,020 --> 00:47:28,760 Again, there's no answer to Excel. 859 00:47:28,760 --> 00:47:31,290 860 00:47:31,290 --> 00:47:34,740 Right, you can't say calculate the answer to Excel. 861 00:47:34,740 --> 00:47:36,240 Because whatever-- 862 00:47:36,240 --> 00:47:38,590 so the right answer for Excel depends on, what's the 863 00:47:38,590 --> 00:47:40,490 sequence of buttons that you're pressing, and what's 864 00:47:40,490 --> 00:47:42,510 the sequence of pull-down menus that you're doing, and 865 00:47:42,510 --> 00:47:44,340 all that sort of stuff. 866 00:47:44,340 --> 00:47:47,010 So graphical user interfaces are processes. 867 00:47:47,010 --> 00:47:50,010 They're things that evolve over time. 868 00:47:50,010 --> 00:47:52,400 So they take a sequence of inputs, and they generate a 869 00:47:52,400 --> 00:47:56,540 sequence of outputs, just like a bank does. 870 00:47:56,540 --> 00:47:58,430 Controllers. 871 00:47:58,430 --> 00:48:01,950 How do you make a robotic steerer? 872 00:48:01,950 --> 00:48:03,810 That's a process. 873 00:48:03,810 --> 00:48:04,900 There are inputs-- 874 00:48:04,900 --> 00:48:07,130 so for example, where are you in the middle of the lane? 875 00:48:07,130 --> 00:48:08,640 What time is it? 876 00:48:08,640 --> 00:48:10,760 How many pedestrians are you about to hit? 877 00:48:10,760 --> 00:48:12,490 There's all of those kinds of inputs. 878 00:48:12,490 --> 00:48:14,540 And then there is things that you output-- 879 00:48:14,540 --> 00:48:17,480 which is like, keep going. 880 00:48:17,480 --> 00:48:20,545 So some of the steering rules are particularly simple. 881 00:48:20,545 --> 00:48:23,520 Other steering rules are you know, avoid the guy this-- 882 00:48:23,520 --> 00:48:24,450 well, anyway. 883 00:48:24,450 --> 00:48:29,590 So the idea is that when you were controlling processes, 884 00:48:29,590 --> 00:48:31,790 we're going to want to think about other kinds of 885 00:48:31,790 --> 00:48:34,310 programming structures. 886 00:48:34,310 --> 00:48:37,070 And even though the programming structures are 887 00:48:37,070 --> 00:48:38,600 going to be different, we're still going to want to have 888 00:48:38,600 --> 00:48:41,630 this idea of modularity. 889 00:48:41,630 --> 00:48:44,230 We're going to want to be able to think about, what are the 890 00:48:44,230 --> 00:48:48,440 primitives that we have, how can we combine them, what are 891 00:48:48,440 --> 00:48:50,050 the important abstractions, and how 892 00:48:50,050 --> 00:48:51,390 do we capture patterns? 893 00:48:51,390 --> 00:48:54,620 We're still going to want to do PCAP. 894 00:48:54,620 --> 00:48:58,430 But we're going to want to do PCAP at a much higher level. 895 00:48:58,430 --> 00:49:02,390 And the programming module that I want to introduce is 896 00:49:02,390 --> 00:49:04,900 the idea of a state machine. 897 00:49:04,900 --> 00:49:08,410 A state machine is a very convenient structure to 898 00:49:08,410 --> 00:49:11,930 capture the behavior of a process. 899 00:49:11,930 --> 00:49:15,520 A state machine has an input, a state, and an output. 900 00:49:15,520 --> 00:49:19,330 The idea is that it's a process. 901 00:49:19,330 --> 00:49:21,830 It's operated upon in steps. 902 00:49:21,830 --> 00:49:25,170 Every step there's a new input. 903 00:49:25,170 --> 00:49:28,540 From that input, the state machine can calculate an 904 00:49:28,540 --> 00:49:32,440 output and the next state. 905 00:49:32,440 --> 00:49:35,380 By keeping track of the state, this state machine can 906 00:49:35,380 --> 00:49:40,620 remember everything it needs to know so that it can 907 00:49:40,620 --> 00:49:43,620 continue the process into the future. 908 00:49:43,620 --> 00:49:46,370 So the idea is that this is going to represent a 909 00:49:46,370 --> 00:49:49,740 fundamental programming element, that we'll be able to 910 00:49:49,740 --> 00:49:54,060 use to construct things that are like processes. 911 00:49:54,060 --> 00:49:58,270 And in particular, we use this to represent the calculations 912 00:49:58,270 --> 00:50:00,120 that are done within our robot. 913 00:50:00,120 --> 00:50:04,060 We'll think about the robot as being a process. 914 00:50:04,060 --> 00:50:06,580 It's not got an answer, you can't ask the question, what's 915 00:50:06,580 --> 00:50:08,570 the answer, to the robot. 916 00:50:08,570 --> 00:50:11,580 But you can answer the question, if I were trying to 917 00:50:11,580 --> 00:50:17,510 steer and the sonar said (x,y,z), how fast should you 918 00:50:17,510 --> 00:50:18,970 turn the wheels? 919 00:50:18,970 --> 00:50:21,130 You can think about that as a state machine. 920 00:50:21,130 --> 00:50:23,140 There's some state of the robot. 921 00:50:23,140 --> 00:50:24,610 There are some inputs-- 922 00:50:24,610 --> 00:50:26,850 which is what the sonars are currently telling us, and 923 00:50:26,850 --> 00:50:27,860 there's some output-- 924 00:50:27,860 --> 00:50:30,050 which is how fast we're driving the wheels. 925 00:50:30,050 --> 00:50:34,160 So we want to think about this kind of a representation for 926 00:50:34,160 --> 00:50:39,440 processes that evolve over time. 927 00:50:39,440 --> 00:50:44,000 OK, here's a very simple example, a turnstile. 928 00:50:44,000 --> 00:50:49,830 So we can think about the turnstile as a state machine. 929 00:50:49,830 --> 00:50:52,550 The turnstile has two states-- 930 00:50:52,550 --> 00:50:54,940 think about getting onto the T-- 931 00:50:54,940 --> 00:50:58,160 either it's locked, or it's not locked. 932 00:50:58,160 --> 00:50:59,760 Those are the two states of the turnstile. 933 00:50:59,760 --> 00:51:02,300 934 00:51:02,300 --> 00:51:04,910 There are some inputs. 935 00:51:04,910 --> 00:51:11,610 The inputs are, I put a coin in it, or I walk through it 936 00:51:11,610 --> 00:51:17,700 and the turnstile turns, or I don't do anything. 937 00:51:17,700 --> 00:51:21,360 And based on those inputs, and based on the current state, 938 00:51:21,360 --> 00:51:25,060 the turnstile has some outputs. 939 00:51:25,060 --> 00:51:28,800 So the turnstile can either allow you to enter, 940 00:51:28,800 --> 00:51:30,940 or ask you to pay. 941 00:51:30,940 --> 00:51:36,250 So the output might be an LED sign that says, please enter. 942 00:51:36,250 --> 00:51:40,130 Or it could have an LED sign that says, please pay. 943 00:51:40,130 --> 00:51:43,870 So those are out all of the elements of a state machine. 944 00:51:43,870 --> 00:51:47,390 And so we can think about a graphical representation for 945 00:51:47,390 --> 00:51:50,560 the turnstile in terms of states. 946 00:51:50,560 --> 00:51:54,640 Here I'm representing the states as circles. 947 00:51:54,640 --> 00:51:57,790 There are two states in the turnstile, the turnstiles is 948 00:51:57,790 --> 00:52:00,680 either locked or unlocked. 949 00:52:00,680 --> 00:52:04,500 You move between states by getting inputs. 950 00:52:04,500 --> 00:52:08,910 So the inputs are represented by the arcs-- 951 00:52:08,910 --> 00:52:14,010 it's the top identifier on each arc is the input, the 952 00:52:14,010 --> 00:52:18,580 bottom identifier is the output, and the special arrow 953 00:52:18,580 --> 00:52:20,400 says I start here. 954 00:52:20,400 --> 00:52:25,020 So the turnstiles start out locked in the morning-- 955 00:52:25,020 --> 00:52:26,210 the turnstile is locked. 956 00:52:26,210 --> 00:52:30,780 If you drop a coin in it, you'll move into the unlocked 957 00:52:30,780 --> 00:52:33,150 state and it will output enter. 958 00:52:33,150 --> 00:52:35,390 It will tell you that it's OK to enter because you've put a 959 00:52:35,390 --> 00:52:37,960 coin in it now. 960 00:52:37,960 --> 00:52:42,170 Then as long as you stay there and do nothing, it'll continue 961 00:52:42,170 --> 00:52:44,020 to say enter-- 962 00:52:44,020 --> 00:52:45,550 none enter. 963 00:52:45,550 --> 00:52:48,360 Or if you keep dropping coins in it, it'll say hey, keep 964 00:52:48,360 --> 00:52:53,040 going, and it'll continue to eat your coins and continue to 965 00:52:53,040 --> 00:52:53,760 say enter-- 966 00:52:53,760 --> 00:52:55,820 being very nice. 967 00:52:55,820 --> 00:52:59,310 So in those cases it remains unlocked, it continues to tell 968 00:52:59,310 --> 00:53:04,690 you that you can enter, and that state persists until you 969 00:53:04,690 --> 00:53:06,850 turn the turnstile. 970 00:53:06,850 --> 00:53:10,470 When you turn the turnstile, this particular turnstile 971 00:53:10,470 --> 00:53:17,040 forgets how many coins you gave it and it simply locks 972 00:53:17,040 --> 00:53:20,450 and it tells you you've got to pay more. 973 00:53:20,450 --> 00:53:24,165 So the idea is that we can capture the desired behavior 974 00:53:24,165 --> 00:53:26,490 of the turnstile-- 975 00:53:26,490 --> 00:53:28,750 the turnstile is a process, it's a thing that 976 00:53:28,750 --> 00:53:29,990 evolves over time. 977 00:53:29,990 --> 00:53:32,390 But we can capture the essence of what we would like the 978 00:53:32,390 --> 00:53:37,290 turnstile to do in terms of this diagram. 979 00:53:37,290 --> 00:53:40,810 We'll call this a state diagram. 980 00:53:40,810 --> 00:53:46,810 And then we can think about behaviors in terms of a set of 981 00:53:46,810 --> 00:53:49,630 outputs as a function of time. 982 00:53:49,630 --> 00:53:53,030 So imagine that as a function of time-- 983 00:53:53,030 --> 00:53:57,090 say I started in the state locked, and 984 00:53:57,090 --> 00:54:00,520 the input is nothing. 985 00:54:00,520 --> 00:54:05,090 So you wake up in the morning, you go to the T, overnight the 986 00:54:05,090 --> 00:54:07,100 turnstiles have all been locked. 987 00:54:07,100 --> 00:54:10,030 They all say that they're locked, they all say, pay, as 988 00:54:10,030 --> 00:54:11,150 their output. 989 00:54:11,150 --> 00:54:15,420 If I don't do anything it just sits there and it says pay. 990 00:54:15,420 --> 00:54:19,750 If I drop a coin, it says enter and it moves into the 991 00:54:19,750 --> 00:54:23,020 unlocked state. 992 00:54:23,020 --> 00:54:24,830 If I don't do anything enter persists 993 00:54:24,830 --> 00:54:28,050 and it stays unlocked. 994 00:54:28,050 --> 00:54:30,820 If I walk through it, it eats the coin and it says, OK, you 995 00:54:30,820 --> 00:54:34,120 gotta pay now, and it locks. 996 00:54:34,120 --> 00:54:36,900 So you can think about the evolution of this process-- 997 00:54:36,900 --> 00:54:40,960 the evolution of the turnstile in terms of the diagram with 998 00:54:40,960 --> 00:54:42,210 regard to time. 999 00:54:42,210 --> 00:54:44,530 1000 00:54:44,530 --> 00:54:49,820 And the idea then is that this is a kind of a representation 1001 00:54:49,820 --> 00:54:53,240 that allows us to succinctly capture the important 1002 00:54:53,240 --> 00:54:56,710 information about how processes work. 1003 00:54:56,710 --> 00:54:59,940 1004 00:54:59,940 --> 00:55:04,120 One of the important features of this representation is that 1005 00:55:04,120 --> 00:55:08,690 it removes you one level away from the looping structure. 1006 00:55:08,690 --> 00:55:11,710 Somewhere somebody's keeping track of the loop. 1007 00:55:11,710 --> 00:55:14,760 Something's going from time 0 to time 1, to time 2, to 3 -- 1008 00:55:14,760 --> 00:55:16,000 we'll talk about that later. 1009 00:55:16,000 --> 00:55:20,360 But for the time being, this representation focuses on what 1010 00:55:20,360 --> 00:55:24,070 do you do at each instance in time? 1011 00:55:24,070 --> 00:55:29,090 So it's a way of tearing apart the time part from the state 1012 00:55:29,090 --> 00:55:30,800 transition part. 1013 00:55:30,800 --> 00:55:35,590 So separate out the loop from the essence, it's very much 1014 00:55:35,590 --> 00:55:39,230 like the functional example that I did. 1015 00:55:39,230 --> 00:55:42,240 The functions divorce themselves from the looping 1016 00:55:42,240 --> 00:55:45,690 structure that we saw in the imperative approach, and you 1017 00:55:45,690 --> 00:55:48,250 could define the functions independent of the looping. 1018 00:55:48,250 --> 00:55:49,640 We're doing the same thing here. 1019 00:55:49,640 --> 00:55:52,130 We can define the state machine representation 1020 00:55:52,130 --> 00:55:54,280 independent of the looping. 1021 00:55:54,280 --> 00:55:56,840 And most importantly, this idea of 1022 00:55:56,840 --> 00:55:58,090 state machines is modular. 1023 00:55:58,090 --> 00:56:00,810 1024 00:56:00,810 --> 00:56:03,420 Let me show you how that plays out when we 1025 00:56:03,420 --> 00:56:05,340 think about the robot. 1026 00:56:05,340 --> 00:56:08,620 Think about the problem that I showed you last time where 1027 00:56:08,620 --> 00:56:14,500 we're trying to have the robot go from point A to point B. 1028 00:56:14,500 --> 00:56:17,900 Where, for example, it knows where it is -- say it has GPS 1029 00:56:17,900 --> 00:56:20,260 or something. 1030 00:56:20,260 --> 00:56:21,230 It knows-- 1031 00:56:21,230 --> 00:56:26,630 from a map say, where it wants to be, but it has no idea of 1032 00:56:26,630 --> 00:56:31,310 the obstacles between where it is and where it wants to be. 1033 00:56:31,310 --> 00:56:33,610 So we can think about that kind of a problem-- we looked 1034 00:56:33,610 --> 00:56:35,350 at this last time. 1035 00:56:35,350 --> 00:56:37,940 It takes a step, it uses its sonars-- 1036 00:56:37,940 --> 00:56:41,640 which are depicted by these lines, to infer that there are 1037 00:56:41,640 --> 00:56:43,020 some walls-- 1038 00:56:43,020 --> 00:56:45,670 that's the black dots. 1039 00:56:45,670 --> 00:56:48,660 So it gets a reflection off the sonar that tells it that 1040 00:56:48,660 --> 00:56:50,100 there's some obstacle in the way. 1041 00:56:50,100 --> 00:56:52,600 That means it's not a good idea to try to plow 1042 00:56:52,600 --> 00:56:56,310 straightforward, so if I back up, the original plan, it had 1043 00:56:56,310 --> 00:56:59,600 no idea what was between it and its destination, so its 1044 00:56:59,600 --> 00:57:01,370 plan was just buzz straight through. 1045 00:57:01,370 --> 00:57:05,130 1046 00:57:05,130 --> 00:57:09,490 At the end of its first step, it has got back sonar reports 1047 00:57:09,490 --> 00:57:12,090 that tell it that there's a wall here, and here, and here, 1048 00:57:12,090 --> 00:57:14,700 and here, and here, and here. 1049 00:57:14,700 --> 00:57:18,270 And based on where the wall is, and the size of the robot, 1050 00:57:18,270 --> 00:57:21,280 it can't get into any of these red squares. 1051 00:57:21,280 --> 00:57:23,550 It's too big. 1052 00:57:23,550 --> 00:57:26,980 So it knows its original path, which went from here to here, 1053 00:57:26,980 --> 00:57:30,820 isn't going to work because it can't fit through. 1054 00:57:30,820 --> 00:57:36,990 So it computes a new path, and then repeat. 1055 00:57:36,990 --> 00:57:38,620 So the idea is that we're solving a 1056 00:57:38,620 --> 00:57:41,470 very complicated problem-- 1057 00:57:41,470 --> 00:57:44,680 the robot 's solving a very complicated problem, and what 1058 00:57:44,680 --> 00:57:46,710 I'd like to do now is think through a 1059 00:57:46,710 --> 00:57:48,290 solution to that problem. 1060 00:57:48,290 --> 00:57:53,840 As the robot's moving along, on every step it's getting 1061 00:57:53,840 --> 00:57:54,740 some new input-- 1062 00:57:54,740 --> 00:57:56,530 it's behaving just like a state machine. 1063 00:57:56,530 --> 00:57:59,850 On every step it gets new input from the sonars. 1064 00:57:59,850 --> 00:58:01,500 Based on that new input, it knows 1065 00:58:01,500 --> 00:58:03,380 where there's new obstacles. 1066 00:58:03,380 --> 00:58:05,550 Based on that knowledge, it has a better idea of 1067 00:58:05,550 --> 00:58:07,140 what the map is. 1068 00:58:07,140 --> 00:58:09,970 Based on that knowledge, it has a better idea of finding a 1069 00:58:09,970 --> 00:58:11,810 plan that might work. 1070 00:58:11,810 --> 00:58:14,770 1071 00:58:14,770 --> 00:58:17,310 And then based on that knowledge, it knows how to 1072 00:58:17,310 --> 00:58:18,810 tell the wheels to move forward. 1073 00:58:18,810 --> 00:58:20,695 So think about where it is right now. 1074 00:58:20,695 --> 00:58:23,400 1075 00:58:23,400 --> 00:58:28,880 It has done, logically, three different things. 1076 00:58:28,880 --> 00:58:32,270 It has figured out where the walls are. 1077 00:58:32,270 --> 00:58:35,940 That's the thing represented in black and red. 1078 00:58:35,940 --> 00:58:37,545 We'll call that -- it made a map. 1079 00:58:37,545 --> 00:58:40,400 1080 00:58:40,400 --> 00:58:42,760 Given the map, it made a plan-- 1081 00:58:42,760 --> 00:58:44,010 that's the blue thing. 1082 00:58:44,010 --> 00:58:46,490 1083 00:58:46,490 --> 00:58:51,180 Given the plan, it figured out how to turn the wheels. 1084 00:58:51,180 --> 00:58:53,820 It's going straight ahead. 1085 00:58:53,820 --> 00:58:57,690 So there are logically three things going on, 1086 00:58:57,690 --> 00:59:00,200 all at the same time. 1087 00:59:00,200 --> 00:59:03,320 You can imagine writing an imperative program to capture 1088 00:59:03,320 --> 00:59:06,930 that behavior, but that's complicated. 1089 00:59:06,930 --> 00:59:09,100 Not impossible, you would structure it 1090 00:59:09,100 --> 00:59:11,375 as a bunch of loops. 1091 00:59:11,375 --> 00:59:12,520 You know, it would-- 1092 00:59:12,520 --> 00:59:13,840 unless you're a crack programmer, and 1093 00:59:13,840 --> 00:59:15,646 I'm sure you are-- 1094 00:59:15,646 --> 00:59:17,920 it will end up being an ugly program. 1095 00:59:17,920 --> 00:59:22,660 The idea is, that by using the state machine representation 1096 00:59:22,660 --> 00:59:24,640 we'll be able to think about how to pull 1097 00:59:24,640 --> 00:59:25,920 apart those three pieces. 1098 00:59:25,920 --> 00:59:28,950 1099 00:59:28,950 --> 00:59:34,130 So in particular, we can think about the state machine for 1100 00:59:34,130 --> 00:59:35,010 the robot-- 1101 00:59:35,010 --> 00:59:38,030 which would take the sensory input from the sonars and turn 1102 00:59:38,030 --> 00:59:41,670 it into an action, which is turning the wheels-- 1103 00:59:41,670 --> 00:59:44,320 we can think about that as having three modules. 1104 00:59:44,320 --> 00:59:48,020 There's the mapmaker module, which just looks at the 1105 00:59:48,020 --> 00:59:49,250 sensory input. 1106 00:59:49,250 --> 00:59:52,910 Doesn't care what the plan is, doesn't care how it's turning 1107 00:59:52,910 --> 00:59:54,030 the wheels right now. 1108 00:59:54,030 --> 00:59:56,590 All it the cares about is, what was the -- 1109 00:59:56,590 --> 00:59:59,070 what's my current state? 1110 00:59:59,070 --> 01:00:01,660 And what new information can I infer about the 1111 01:00:01,660 --> 01:00:04,540 map from the sonars? 1112 01:00:04,540 --> 01:00:08,180 So given the sonars and my current state, what's the most 1113 01:00:08,180 --> 01:00:12,620 recent version of the map likely to look like. 1114 01:00:12,620 --> 01:00:15,820 Then there's a planner that says, given the sonars and the 1115 01:00:15,820 --> 01:00:21,360 map, how would I construct this blue line? 1116 01:00:21,360 --> 01:00:26,180 Given my current understanding of the map of the world, how 1117 01:00:26,180 --> 01:00:30,130 would I get from where I am, to where I want to be? 1118 01:00:30,130 --> 01:00:32,430 That's a plan. 1119 01:00:32,430 --> 01:00:35,170 Then from that plan-- 1120 01:00:35,170 --> 01:00:38,850 say the robot is here, from the plan you can see that the 1121 01:00:38,850 --> 01:00:43,180 thing the robot should do is move straight ahead. 1122 01:00:43,180 --> 01:00:47,200 So the mover can take the heading-- 1123 01:00:47,200 --> 01:00:50,130 the heading is just simply the coordinates of the first 1124 01:00:50,130 --> 01:00:52,980 destination point in the plan. 1125 01:00:52,980 --> 01:00:56,100 So the mover can look at the heading, the first destination 1126 01:00:56,100 --> 01:00:59,100 point, and figure out how to make the wheels turn. 1127 01:00:59,100 --> 01:01:01,970 So the idea is that the state machine representation will 1128 01:01:01,970 --> 01:01:04,920 let us parse a very complicated problem. 1129 01:01:04,920 --> 01:01:06,460 A process-- 1130 01:01:06,460 --> 01:01:11,200 the process by which the robot gets from here to there, a 1131 01:01:11,200 --> 01:01:12,590 very complicated process. 1132 01:01:12,590 --> 01:01:16,140 We're going to be able to break it up into pieces. 1133 01:01:16,140 --> 01:01:19,030 The pieces are going to be much easier. 1134 01:01:19,030 --> 01:01:20,750 They're going to be modular. 1135 01:01:20,750 --> 01:01:25,180 We will be able to write this piece, and debug it and make 1136 01:01:25,180 --> 01:01:27,330 sure that it all works, independent 1137 01:01:27,330 --> 01:01:29,760 of these other pieces. 1138 01:01:29,760 --> 01:01:32,930 Because we just have it do any arbitrary walk around task or 1139 01:01:32,930 --> 01:01:36,790 no walk around at all and ask whether the set of sensory 1140 01:01:36,790 --> 01:01:40,880 inputs generates the correct map. 1141 01:01:40,880 --> 01:01:42,930 Similarly, this will be a module. 1142 01:01:42,930 --> 01:01:45,920 This will be something that we can debug as well without 1143 01:01:45,920 --> 01:01:47,590 having the other pieces working. 1144 01:01:47,590 --> 01:01:50,930 We'll be able to say, OK, well, what if I fed a map that 1145 01:01:50,930 --> 01:01:54,770 I hand constructed to the robot-- 1146 01:01:54,770 --> 01:01:57,160 ignore this, just forget this, assume 1147 01:01:57,160 --> 01:01:58,590 there is none of these-- 1148 01:01:58,590 --> 01:02:02,340 I can hand make a map, feed it to this guy, give it sensory 1149 01:02:02,340 --> 01:02:05,890 input and see if it comes up with the right heading. 1150 01:02:05,890 --> 01:02:08,020 It's just like in that functional approach example 1151 01:02:08,020 --> 01:02:09,290 that I did. 1152 01:02:09,290 --> 01:02:12,230 Having made the individual functions, we were able to 1153 01:02:12,230 --> 01:02:15,670 test them individually because they were modules. 1154 01:02:15,670 --> 01:02:18,680 Having made these individual state machines, we'll be able 1155 01:02:18,680 --> 01:02:22,320 to test them individually because they're modules. 1156 01:02:22,320 --> 01:02:25,090 Then at the end we'll be able to paste them all together and 1157 01:02:25,090 --> 01:02:26,830 get a very complicated behavior-- 1158 01:02:26,830 --> 01:02:29,980 much more complicated than you would expect from the sum of 1159 01:02:29,980 --> 01:02:31,680 the three programming activities. 1160 01:02:31,680 --> 01:02:32,690 That's what we want. 1161 01:02:32,690 --> 01:02:33,960 That's how we want to structure things. 1162 01:02:33,960 --> 01:02:37,470 We want to be able to combine simple things and get 1163 01:02:37,470 --> 01:02:39,950 something that seems more powerful than the linear 1164 01:02:39,950 --> 01:02:41,565 combination, because it is. 1165 01:02:41,565 --> 01:02:44,440 1166 01:02:44,440 --> 01:02:45,840 Okay, so that's the goal. 1167 01:02:45,840 --> 01:02:48,900 To do that, we're going to invent some new Python 1168 01:02:48,900 --> 01:02:49,610 structures. 1169 01:02:49,610 --> 01:02:52,450 And we're going to think about the representation of the 1170 01:02:52,450 --> 01:02:59,050 state machine in Python and we will use objects. 1171 01:02:59,050 --> 01:03:03,020 In fact, we use objects at three levels. 1172 01:03:03,020 --> 01:03:06,200 We'll think about the highest level of abstraction of this 1173 01:03:06,200 --> 01:03:08,490 problem as a state machine. 1174 01:03:08,490 --> 01:03:11,490 So there's going to be state machine class. 1175 01:03:11,490 --> 01:03:14,620 The state machine class is going to have all the things 1176 01:03:14,620 --> 01:03:18,100 in it that all state machines have to know about. 1177 01:03:18,100 --> 01:03:20,970 All state machines, as we define them, are going to have 1178 01:03:20,970 --> 01:03:28,300 to know how to start, how to make one step, and how to 1179 01:03:28,300 --> 01:03:31,960 combine single steps into a sequence of steps-- and we'll 1180 01:03:31,960 --> 01:03:34,490 call that operation of transduction. 1181 01:03:34,490 --> 01:03:39,070 So if you give me a list of inputs, transduce will make a 1182 01:03:39,070 --> 01:03:41,120 list of outputs. 1183 01:03:41,120 --> 01:03:43,370 So all state machines are going to be able to-- 1184 01:03:43,370 --> 01:03:46,580 all state machines are going to have to know how to start, 1185 01:03:46,580 --> 01:03:49,710 step, and transduce. 1186 01:03:49,710 --> 01:03:52,390 Then for particular types of state machines-- 1187 01:03:52,390 --> 01:03:56,310 like the turnstile, we will generate a subclass. 1188 01:03:56,310 --> 01:03:58,960 1189 01:03:58,960 --> 01:04:02,730 The subclass of turnstiles are going to have to know-- all of 1190 01:04:02,730 --> 01:04:05,280 those are going to have to do some other things. 1191 01:04:05,280 --> 01:04:09,180 All turnstiles are going to have to have a rule for what 1192 01:04:09,180 --> 01:04:13,250 happens when you're in state A and you get input i-- 1193 01:04:13,250 --> 01:04:14,840 what should you do? 1194 01:04:14,840 --> 01:04:17,820 Well there's going to be a general pattern that all 1195 01:04:17,820 --> 01:04:20,380 turnstiles will subscribe to. 1196 01:04:20,380 --> 01:04:24,880 We'll put those in the subclass, turnstile. 1197 01:04:24,880 --> 01:04:28,450 Then individual turnstiles. 1198 01:04:28,450 --> 01:04:30,700 The first one in the Kendall stop, the second one in the 1199 01:04:30,700 --> 01:04:33,010 Kendall stop, the first one in the Central stop, the third 1200 01:04:33,010 --> 01:04:34,820 one in the Harvard stop-- 1201 01:04:34,820 --> 01:04:37,250 particular turnstiles will be instances of 1202 01:04:37,250 --> 01:04:40,390 the turnstile class. 1203 01:04:40,390 --> 01:04:43,770 So the way this plays out, we'll have a generic state 1204 01:04:43,770 --> 01:04:47,500 machine class defined here. 1205 01:04:47,500 --> 01:04:51,750 The state machine class will have a method, start. 1206 01:04:51,750 --> 01:04:56,240 Start will create the instance variable, state. 1207 01:04:56,240 --> 01:05:00,490 Every instance of a turnstile has to remember where it is, 1208 01:05:00,490 --> 01:05:02,510 that's an instance variable. 1209 01:05:02,510 --> 01:05:05,360 That instance variable gets created by the start routine. 1210 01:05:05,360 --> 01:05:07,890 So the very first thing you do if you want to talk about a 1211 01:05:07,890 --> 01:05:12,400 new turnstile, is you have to instantiate the turnstile. 1212 01:05:12,400 --> 01:05:14,580 Then you have to make an instance-- 1213 01:05:14,580 --> 01:05:17,960 and you do that by calling start. 1214 01:05:17,960 --> 01:05:20,160 Every state machine has to have a start routine. 1215 01:05:20,160 --> 01:05:25,040 Every start routine will do this-- it'll create an 1216 01:05:25,040 --> 01:05:26,940 instance variable. 1217 01:05:26,940 --> 01:05:31,100 Every state machine has to know how to take a step. 1218 01:05:31,100 --> 01:05:38,100 We will make a generic method called, getNextValues, which 1219 01:05:38,100 --> 01:05:44,980 will include all of the rules for how the class turnstile 1220 01:05:44,980 --> 01:05:52,020 generates a new output, and a new state from the implant. 1221 01:05:52,020 --> 01:05:57,180 And every subclass of state machine will have to define 1222 01:05:57,180 --> 01:05:59,140 what one of those looks like. 1223 01:05:59,140 --> 01:06:04,370 The important thing here is that every state machine has 1224 01:06:04,370 --> 01:06:08,100 to have a step routine, and the way we've decided to 1225 01:06:08,100 --> 01:06:11,830 implement the step routine is to call the getNextValues, 1226 01:06:11,830 --> 01:06:14,690 that is particular to the subclass of interest. 1227 01:06:14,690 --> 01:06:18,390 So for example, the getNextValues for a turnstile, 1228 01:06:18,390 --> 01:06:22,710 might be different from the getNextValues for a planner or 1229 01:06:22,710 --> 01:06:23,960 a for a mapper. 1230 01:06:23,960 --> 01:06:28,460 1231 01:06:28,460 --> 01:06:33,970 Then we will subclass state machine according to the kind 1232 01:06:33,970 --> 01:06:35,590 of state machine we're making. 1233 01:06:35,590 --> 01:06:40,380 A planner, a mapper, a mover, a turnstile. 1234 01:06:40,380 --> 01:06:43,790 So a turnstile will be a class, which is a subclass of 1235 01:06:43,790 --> 01:06:47,170 state machine, and that's where we'll define how do you 1236 01:06:47,170 --> 01:06:48,470 do getNextValues. 1237 01:06:48,470 --> 01:06:52,870 If you're a turnstile, here's the way you ought to do 1238 01:06:52,870 --> 01:06:55,330 getNextValues. 1239 01:06:55,330 --> 01:06:57,990 When I call getNextValues, I'll tell you your current 1240 01:06:57,990 --> 01:07:01,600 state and the current input, and from those two you ought 1241 01:07:01,600 --> 01:07:07,070 to be able to figure out the next state and the output. 1242 01:07:07,070 --> 01:07:15,610 So the getNextValues method for the turnstile class ought 1243 01:07:15,610 --> 01:07:18,170 to take state and input-- 1244 01:07:18,170 --> 01:07:22,070 the input, and the current state, and it generates a 1245 01:07:22,070 --> 01:07:29,480 tuple, which is the new state and the output. 1246 01:07:29,480 --> 01:07:32,470 And this is the rule by which it happens. 1247 01:07:32,470 --> 01:07:37,420 All turnstiles also have the same start state. 1248 01:07:37,420 --> 01:07:41,260 So if you look back again at state machine, state machine 1249 01:07:41,260 --> 01:07:44,470 created the instance variable, state, by 1250 01:07:44,470 --> 01:07:47,900 looking at start's state. 1251 01:07:47,900 --> 01:07:51,260 All turnstiles have the same start state, 1252 01:07:51,260 --> 01:07:54,930 they all start locked. 1253 01:07:54,930 --> 01:07:58,280 And then finally, the way we'll use this, is we will 1254 01:07:58,280 --> 01:08:02,540 instantiate a turnstile, we will make an instance of 1255 01:08:02,540 --> 01:08:06,690 turnstile, put it into TS, turnstile, so this could be 1256 01:08:06,690 --> 01:08:09,900 Central Square 16, for example. 1257 01:08:09,900 --> 01:08:13,870 And then that instance, we'll be able to do things like 1258 01:08:13,870 --> 01:08:16,970 start, step, and transduce. 1259 01:08:16,970 --> 01:08:22,189 So if I transduced this the input, none, coin, none, turn, 1260 01:08:22,189 --> 01:08:25,500 turn, coin, coin, on a particular turnstile, I'll 1261 01:08:25,500 --> 01:08:28,930 generate some sequence of outputs like so. 1262 01:08:28,930 --> 01:08:31,760 1263 01:08:31,760 --> 01:08:34,250 So that's a complicated example using turnstiles. 1264 01:08:34,250 --> 01:08:35,660 Let me do something simpler just to make 1265 01:08:35,660 --> 01:08:37,279 sure you get the idea. 1266 01:08:37,279 --> 01:08:41,300 Let's think about a simpler class, a subclass of state 1267 01:08:41,300 --> 01:08:45,120 machines, a subclass called accumulator. 1268 01:08:45,120 --> 01:08:50,939 That subclass always has a start state of 0, and has a 1269 01:08:50,939 --> 01:08:54,790 getNextValues that returns the same value for the next state 1270 01:08:54,790 --> 01:08:57,040 and for the output. 1271 01:08:57,040 --> 01:09:00,569 It always adds the current state to the input-- 1272 01:09:00,569 --> 01:09:02,029 hence the name accumulator. 1273 01:09:02,029 --> 01:09:07,160 It accumulates the input by taking the current state, 1274 01:09:07,160 --> 01:09:10,970 adding the currently input to generate a new state-- 1275 01:09:10,970 --> 01:09:13,270 that's just like a bank account. 1276 01:09:13,270 --> 01:09:18,830 The bank account would accumulate transactions. 1277 01:09:18,830 --> 01:09:25,210 So if the input to the accumulator is 7, then the 1278 01:09:25,210 --> 01:09:29,410 state gets incremented by 7, and the output is the value of 1279 01:09:29,410 --> 01:09:30,330 the new state. 1280 01:09:30,330 --> 01:09:33,210 So that's what this says, the starting state is always 0, 1281 01:09:33,210 --> 01:09:36,910 the getNextValues always returns for this new state-- 1282 01:09:36,910 --> 01:09:40,670 state plus input, and for the current output, the same thing 1283 01:09:40,670 --> 01:09:43,399 as the current state. 1284 01:09:43,399 --> 01:09:44,649 Everybody's clear? 1285 01:09:44,649 --> 01:09:48,500 1286 01:09:48,500 --> 01:09:52,160 So the question is, what would happen if I did this sequence 1287 01:09:52,160 --> 01:09:53,689 of operations? 1288 01:09:53,689 --> 01:09:56,410 Let's say that I have the state machine class, I have 1289 01:09:56,410 --> 01:09:59,220 the accumulator subclass. 1290 01:09:59,220 --> 01:10:03,500 I make an instance A, I do some stuff to A, I make an 1291 01:10:03,500 --> 01:10:05,960 instance B. I do some stuff to B, I do some stuff to 1292 01:10:05,960 --> 01:10:06,820 A, and I type this. 1293 01:10:06,820 --> 01:10:08,070 What gets printed? 1294 01:10:08,070 --> 01:10:11,240 1295 01:10:11,240 --> 01:10:13,140 Take 30 seconds, talk to your neighbor, figure out 1296 01:10:13,140 --> 01:10:13,760 what the answer is. 1297 01:10:13,760 --> 01:12:58,030 [AUDIENCE DISCUSSION] 1298 01:12:58,030 --> 01:12:59,280 PROFESSOR: OK. 1299 01:12:59,280 --> 01:13:01,640 1300 01:13:01,640 --> 01:13:04,620 What will get printed by the print statement? 1301 01:13:04,620 --> 01:13:06,690 Answer (1), (2), (3), (4), or (5). 1302 01:13:06,690 --> 01:13:10,752 Everybody raise your hand with an answer. 1303 01:13:10,752 --> 01:13:13,560 Excellent, excellent, almost 100%. 1304 01:13:13,560 --> 01:13:16,820 I don't think I see a single wrong answer. 1305 01:13:16,820 --> 01:13:20,413 So everybody seems to be saying (2). 1306 01:13:20,413 --> 01:13:23,490 (2), OK, so what's going on? 1307 01:13:23,490 --> 01:13:26,860 So A is an accumulator, we start it, we step it. 1308 01:13:26,860 --> 01:13:29,740 B is an accumulator, we start it, we step it, we step. 1309 01:13:29,740 --> 01:13:33,790 So what is going to be A, how did you get five? 1310 01:13:33,790 --> 01:13:36,460 Well, A started at 0 that's what the start 1311 01:13:36,460 --> 01:13:39,950 method does, right? 1312 01:13:39,950 --> 01:13:42,750 Stepping it stepped it to 7. 1313 01:13:42,750 --> 01:13:46,730 B made a new one, we can ignore that because it's a 1314 01:13:46,730 --> 01:13:48,690 separate instance. 1315 01:13:48,690 --> 01:13:53,600 The idea is that the state is associated with the instance. 1316 01:13:53,600 --> 01:13:58,250 So when we perturb the state of B by doing B.step, we are 1317 01:13:58,250 --> 01:14:00,420 touching the state of A-- 1318 01:14:00,420 --> 01:14:02,290 because they're instance variables. 1319 01:14:02,290 --> 01:14:04,050 So that means when we decrement it, we're 1320 01:14:04,050 --> 01:14:05,810 decrementing the 7 to get 5. 1321 01:14:05,810 --> 01:14:08,370 1322 01:14:08,370 --> 01:14:09,720 OK, seems reasonable. 1323 01:14:09,720 --> 01:14:10,970 So the answer is either (1), or (2), or none. 1324 01:14:10,970 --> 01:14:14,000 1325 01:14:14,000 --> 01:14:20,510 Why is it the same (21, 21) (21, 21), when we called the 1326 01:14:20,510 --> 01:14:26,470 A.getNextValues, and here we're calling the B. Why are 1327 01:14:26,470 --> 01:14:27,720 they the same? 1328 01:14:27,720 --> 01:14:30,020 1329 01:14:30,020 --> 01:14:32,910 AUDIENCE: Because it sets the state [INAUDIBLE]. 1330 01:14:32,910 --> 01:14:38,540 PROFESSOR: So getNextValues is a pure function. 1331 01:14:38,540 --> 01:14:43,900 So it gets passed in the state, the first number is the 1332 01:14:43,900 --> 01:14:48,400 state, the second number is the input. 1333 01:14:48,400 --> 01:14:50,780 So it doesn't pay any attention to the instance 1334 01:14:50,780 --> 01:14:55,870 variable state, it uses the thing they got passed in. 1335 01:14:55,870 --> 01:14:59,400 Furthermore, the getNextValues associated with A, is 1336 01:14:59,400 --> 01:15:02,430 precisely the same as the getNextValues associated with 1337 01:15:02,430 --> 01:15:08,240 B, because getNextValues is something that's in the 1338 01:15:08,240 --> 01:15:11,140 accumulator subclass. 1339 01:15:11,140 --> 01:15:13,980 So they're exactly the same because it's the same method. 1340 01:15:13,980 --> 01:15:16,730 So what should be in your head, is a picture 1341 01:15:16,730 --> 01:15:19,160 that looks like this. 1342 01:15:19,160 --> 01:15:22,880 When we said create a state machine, that was something we 1343 01:15:22,880 --> 01:15:28,190 put in our library, and that makes this environment. 1344 01:15:28,190 --> 01:15:34,300 When we said subclass of state machine to make accumulator, 1345 01:15:34,300 --> 01:15:39,020 that made a new class, a new environment. 1346 01:15:39,020 --> 01:15:42,890 And then when we made A and B by saying that A equals 1347 01:15:42,890 --> 01:15:43,880 accumulator, and B equals 1348 01:15:43,880 --> 01:15:46,900 accumulator, that made instances. 1349 01:15:46,900 --> 01:15:50,910 The instances were initially empty, but when I say A.start, 1350 01:15:50,910 --> 01:15:54,850 that created the state variable in the A instance, 1351 01:15:54,850 --> 01:15:58,630 and in the B instance, and associated values with them. 1352 01:15:58,630 --> 01:16:00,220 So with the picture that you're supposed to have in 1353 01:16:00,220 --> 01:16:03,010 mind, is that there's an environment associated with 1354 01:16:03,010 --> 01:16:05,580 state machine. 1355 01:16:05,580 --> 01:16:10,150 There's a separate environment associated with accumulator, 1356 01:16:10,150 --> 01:16:12,730 but just one of those. 1357 01:16:12,730 --> 01:16:15,250 But there's two instances. 1358 01:16:15,250 --> 01:16:17,190 So there's two sets of instance variables, one 1359 01:16:17,190 --> 01:16:22,420 associated with A and B. So the answer was number (2). 1360 01:16:22,420 --> 01:16:26,090 Now the robot example was supposed to motivate this idea 1361 01:16:26,090 --> 01:16:28,690 that what we're going to do with state machines is put 1362 01:16:28,690 --> 01:16:31,440 them together modularly. 1363 01:16:31,440 --> 01:16:34,140 So what we're going to do-- and you start to do that this 1364 01:16:34,140 --> 01:16:37,820 week, and also continuing into next week, we'll figure out 1365 01:16:37,820 --> 01:16:42,350 how to compose state machine M1 and M2 in a cascade. 1366 01:16:42,350 --> 01:16:45,670 That means the output of the first one becomes the input to 1367 01:16:45,670 --> 01:16:47,740 the second one. 1368 01:16:47,740 --> 01:16:50,110 We'll put things together in parallel, we'll put things 1369 01:16:50,110 --> 01:16:51,450 together with feedback. 1370 01:16:51,450 --> 01:16:55,140 So what we'll do, is we'll figure out operators. 1371 01:16:55,140 --> 01:16:55,720 PCAP-- 1372 01:16:55,720 --> 01:16:57,950 primitives, means of combination, 1373 01:16:57,950 --> 01:16:59,280 abstraction, patterns. 1374 01:16:59,280 --> 01:17:02,720 The primitives are going to be the state machines, the ways 1375 01:17:02,720 --> 01:17:06,000 we combine them are going to be these kinds of structures. 1376 01:17:06,000 --> 01:17:10,140 Cascade them, put them in parallel, that kind of stuff. 1377 01:17:10,140 --> 01:17:13,840 And that's going to allow us to make complicated brains out 1378 01:17:13,840 --> 01:17:15,400 of simple ones. 1379 01:17:15,400 --> 01:17:18,550 Here's a very simple example, what if I had a state machine 1380 01:17:18,550 --> 01:17:21,710 A, which is an accumulator, so A is an instance of 1381 01:17:21,710 --> 01:17:22,960 accumulator. 1382 01:17:22,960 --> 01:17:25,410 B is an instance of accumulator, there's two 1383 01:17:25,410 --> 01:17:26,880 separate instances. 1384 01:17:26,880 --> 01:17:36,100 And C is a new state composed by cascading A and B. What 1385 01:17:36,100 --> 01:17:39,565 would happen if I typed out C.transduce so ([7, 3, 4])? 1386 01:17:39,565 --> 01:17:44,960 1387 01:17:44,960 --> 01:17:48,280 What's the answer to C.transduce ([7,3,4])? 1388 01:17:48,280 --> 01:18:42,470 [AUDIENCE DISCUSSION] 1389 01:18:42,470 --> 01:18:46,150 PROFESSOR: So what happens when I transduce C? 1390 01:18:46,150 --> 01:18:52,280 Well C is a composition of A and B. In particular, it's 1391 01:18:52,280 --> 01:18:53,860 this composition. 1392 01:18:53,860 --> 01:18:58,980 C is just the cascade of A into B. What that means is 1393 01:18:58,980 --> 01:19:02,620 that if I put some sequence of inputs into the first machine, 1394 01:19:02,620 --> 01:19:06,340 and if I put some sequence of the inputs into C, it's the 1395 01:19:06,340 --> 01:19:09,950 same as putting it into A. 1396 01:19:09,950 --> 01:19:14,440 The output of the composite machine is the output of B. 1397 01:19:14,440 --> 01:19:18,590 And the input to B is the same as the output of A. So the 1398 01:19:18,590 --> 01:19:22,040 ([7,3,4]) goes through A, which is an accumulator, and 1399 01:19:22,040 --> 01:19:24,510 comes out [7, 10, 14]. 1400 01:19:24,510 --> 01:19:28,820 It accumulates, that's what accumulators do. 1401 01:19:28,820 --> 01:19:30,560 That clear? 1402 01:19:30,560 --> 01:19:32,340 Then [7, 10, 14] 1403 01:19:32,340 --> 01:19:34,175 goes into B and comes out [7, 17, 31]. 1404 01:19:34,175 --> 01:19:38,120 1405 01:19:38,120 --> 01:19:42,170 So C, which is the cascade of two accumulators, ends up 1406 01:19:42,170 --> 01:19:44,310 transforming [7, 3, 4] 1407 01:19:44,310 --> 01:19:45,560 into [7, 17, 31]. 1408 01:19:45,560 --> 01:19:49,690 1409 01:19:49,690 --> 01:19:53,370 So that's the idea for how we're going to compose 1410 01:19:53,370 --> 01:19:57,590 complicated behaviors out of simple ones, and that's what 1411 01:19:57,590 --> 01:19:59,240 the assignment is for this week. 1412 01:19:59,240 --> 01:20:08,085