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